agent99 0.0.3 → 0.0.5

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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/A2A_SPEC-dev.md +1829 -0
  3. data/CHANGELOG.md +38 -0
  4. data/COMMITS.md +196 -0
  5. data/DOCS.md +96 -0
  6. data/README.md +212 -84
  7. data/Rakefile +62 -0
  8. data/docs/AI/htm.md +215 -0
  9. data/docs/AI/htm.rb +141 -0
  10. data/docs/AI/htm_demo.db +0 -0
  11. data/docs/AI/notes_on_htm_implementation.md +1319 -0
  12. data/docs/AI/some_code.rb +692 -0
  13. data/docs/advanced-topics/a2a-protocol.md +13 -0
  14. data/docs/{advanced_features.md → advanced-topics/advanced-features.md} +9 -4
  15. data/docs/{control_actions.md → advanced-topics/control-actions.md} +2 -0
  16. data/docs/advanced-topics/model-context-protocol.md +4 -0
  17. data/docs/advanced-topics/multi-agent-processing.md +674 -0
  18. data/docs/agent-development/request-response-handling.md +512 -0
  19. data/docs/agent99_framework/central_registry.md +94 -0
  20. data/docs/agent99_framework/message_client.md +120 -0
  21. data/docs/agent99_framework/registry_client.md +119 -0
  22. data/docs/api-reference/agent99-base.md +463 -0
  23. data/docs/api-reference/message-clients.md +495 -0
  24. data/docs/{api_reference.md → api-reference/overview.md} +14 -4
  25. data/docs/api-reference/registry-client.md +470 -0
  26. data/docs/api-reference/schemas.md +518 -0
  27. data/docs/assets/css/custom.css +27 -0
  28. data/docs/assets/images/agent-lifecycle.svg +73 -0
  29. data/docs/assets/images/agent-registry-process.svg +86 -0
  30. data/docs/assets/images/agent-registry-processes.svg +114 -0
  31. data/docs/assets/images/agent-types-overview.svg +51 -0
  32. data/docs/assets/images/agent99-architecture.svg +85 -0
  33. data/docs/assets/images/agent99_logo.png +0 -0
  34. data/docs/assets/images/control-actions-state.svg +83 -0
  35. data/docs/assets/images/knowledge-graph.svg +77 -0
  36. data/docs/assets/images/message-processing-flow.svg +148 -0
  37. data/docs/assets/images/multi-agent-system.svg +66 -0
  38. data/docs/assets/images/proxy-pattern-sequence.svg +48 -0
  39. data/docs/assets/images/request-flow.svg +97 -0
  40. data/docs/assets/images/request-processing-lifecycle.svg +50 -0
  41. data/docs/assets/images/request-response-sequence.svg +39 -0
  42. data/docs/{agent_lifecycle.md → core-concepts/agent-lifecycle.md} +2 -0
  43. data/docs/core-concepts/agent-types.md +255 -0
  44. data/docs/{architecture.md → core-concepts/architecture.md} +5 -5
  45. data/docs/core-concepts/what-is-an-agent.md +293 -0
  46. data/docs/diagrams/message-flow-sequence.svg +198 -0
  47. data/docs/diagrams/p2p-network-topology.svg +181 -0
  48. data/docs/diagrams/smart-transport-routing.svg +165 -0
  49. data/docs/diagrams/three-layer-architecture.svg +77 -0
  50. data/docs/diagrams/transport-extension-api.svg +309 -0
  51. data/docs/diagrams/transport-extension-architecture.svg +234 -0
  52. data/docs/diagrams/transport-selection-flowchart.svg +264 -0
  53. data/docs/examples/advanced-examples.md +951 -0
  54. data/docs/examples/basic-examples.md +268 -0
  55. data/docs/{agent_discovery.md → framework-components/agent-discovery.md} +9 -5
  56. data/docs/{agent_registry_processes.md → framework-components/agent-registry.md} +9 -3
  57. data/docs/{message_processing.md → framework-components/message-processing.md} +3 -1
  58. data/docs/getting-started/basic-example.md +306 -0
  59. data/docs/getting-started/installation.md +160 -0
  60. data/docs/getting-started/overview.md +64 -0
  61. data/docs/getting-started/quick-start.md +179 -0
  62. data/docs/index.md +97 -0
  63. data/docs/operations/breaking-changes.md +26 -0
  64. data/examples/DEMO.md +148 -0
  65. data/examples/README.md +50 -0
  66. data/examples/agent_watcher.rb +5 -1
  67. data/examples/bad_agent.rb +32 -0
  68. data/examples/chief_agent.rb +17 -6
  69. data/examples/control.rb +16 -7
  70. data/examples/example_agent.rb +16 -3
  71. data/examples/maxwell_agent86.rb +15 -26
  72. data/examples/registry.rb +10 -9
  73. data/examples/run_demo.rb +433 -0
  74. data/lib/agent99/agent_discovery.rb +4 -0
  75. data/lib/agent99/agent_lifecycle.rb +34 -10
  76. data/lib/agent99/amqp_message_client.rb +2 -2
  77. data/lib/agent99/base.rb +6 -2
  78. data/lib/agent99/message_processing.rb +6 -10
  79. data/lib/agent99/registry_client.rb +15 -11
  80. data/lib/agent99/tcp_message_client.rb +183 -0
  81. data/lib/agent99/version.rb +1 -1
  82. data/lib/agent99.rb +1 -1
  83. data/mkdocs.yml +195 -0
  84. data/p2p_plan.md +533 -0
  85. data/p2p_roadmap.md +299 -0
  86. data/registry_plan.md +1818 -0
  87. metadata +93 -30
  88. data/docs/README.md +0 -57
  89. data/docs/diagrams/agent_registry_processes.dot +0 -42
  90. data/docs/diagrams/agent_registry_processes.png +0 -0
  91. data/docs/diagrams/high_level_architecture.dot +0 -26
  92. data/docs/diagrams/high_level_architecture.png +0 -0
  93. data/docs/diagrams/request_flow.dot +0 -42
  94. data/docs/diagrams/request_flow.png +0 -0
  95. /data/docs/{extending_the_framework.md → advanced-topics/extending-the-framework.md} +0 -0
  96. /data/docs/{custom_agent_implementation.md → agent-development/custom-agent-implementation.md} +0 -0
  97. /data/docs/{error_handling_and_logging.md → agent-development/error-handling-and-logging.md} +0 -0
  98. /data/docs/{schema_definition.md → agent-development/schema-definition.md} +0 -0
  99. /data/docs/{messaging_system.md → framework-components/messaging-system.md} +0 -0
  100. /data/docs/{configuration.md → operations/configuration.md} +0 -0
  101. /data/docs/{preformance_considerations.md → operations/performance-considerations.md} +0 -0
  102. /data/docs/{security.md → operations/security.md} +0 -0
  103. /data/docs/{troubleshooting.md → operations/troubleshooting.md} +0 -0
@@ -0,0 +1,692 @@
1
+ # some_code.rb
2
+ # snippets written by the robot
3
+ ############################################
4
+ class KnowledgeNode
5
+ attr_reader :id, :content, :detail_level
6
+
7
+ def initialize(id:, content:, detail_level:)
8
+ @id = id
9
+ @content = content
10
+ @detail_level = detail_level
11
+ @connections = {
12
+ more_general: [],
13
+ more_specific: [],
14
+ related: [],
15
+ }
16
+ end
17
+
18
+ def add_connection(node:, relationship:)
19
+ @connections[relationship] << node
20
+ end
21
+ end
22
+
23
+ class KnowledgeGraph
24
+ def initialize
25
+ @nodes = {}
26
+ end
27
+
28
+ def add_node(node:)
29
+ @nodes[node.id] = node
30
+ end
31
+
32
+ def connect_nodes(from_id:, to_id:, relationship:)
33
+ from_node = @nodes[from_id]
34
+ to_node = @nodes[to_id]
35
+ from_node.add_connection(node: to_node, relationship: relationship)
36
+ end
37
+
38
+ def get_more_specific(node_id:)
39
+ @nodes[node_id].connections[:more_specific]
40
+ end
41
+
42
+ def get_more_general(node_id:)
43
+ @nodes[node_id].connections[:more_general]
44
+ end
45
+ end
46
+
47
+ ############################################
48
+ require "neo4j"
49
+
50
+ class Concept
51
+ include Neo4j::ActiveNode
52
+ property :name, type: String
53
+ property :detail_level, type: Integer
54
+
55
+ has_many :out, :more_specific, type: :SPECIALIZES, model_class: "Concept"
56
+ has_many :in, :more_general, type: :SPECIALIZES, model_class: "Concept"
57
+ end
58
+
59
+ # Create nodes
60
+ general = Concept.create(name: "Science", detail_level: 1)
61
+ specific = Concept.create(name: "Physics", detail_level: 2)
62
+
63
+ # Create relationship
64
+ general.more_specific << specific
65
+
66
+ ############################################
67
+ require "graphviz"
68
+
69
+ graph = GraphViz.new(:G, type: :digraph)
70
+
71
+ node1 = graph.add_nodes("Science")
72
+ node2 = graph.add_nodes("Physics")
73
+
74
+ graph.add_edges(node1, node2)
75
+
76
+ # See knowledge graph visualization at:
77
+ # docs/assets/images/knowledge-graph.svg
78
+ # graph.output(png: "knowledge_graph.png")
79
+
80
+ ############################################
81
+ require "rgl/adjacency"
82
+ require "rgl/dot"
83
+
84
+ graph = RGL::DirectedAdjacencyGraph.new
85
+
86
+ graph.add_edge("Science", "Physics")
87
+ graph.add_edge("Physics", "Quantum Mechanics")
88
+
89
+ graph.write_to_graphic_file("jpg")
90
+
91
+ ############################################
92
+ require "orientdb"
93
+
94
+ database = OrientDB::Database.new(url: "remote:localhost/knowledge_graph")
95
+
96
+ database.create_vertex_type("Concept")
97
+
98
+ science = database.create_vertex("Concept", name: "Science", detail_level: 1)
99
+ physics = database.create_vertex("Concept", name: "Physics", detail_level: 2)
100
+
101
+ database.create_edge("Specializes", science, physics)
102
+
103
+ ############################################
104
+ class KnowledgeNode
105
+ attr_reader :id, :content, :detail_level, :last_accessed
106
+
107
+ def initialize(id:, content:, detail_level:)
108
+ @id = id
109
+ @content = content
110
+ @detail_level = detail_level
111
+ @last_accessed = Time.now
112
+ @connections = {
113
+ more_general: [],
114
+ more_specific: [],
115
+ related: [],
116
+ }
117
+ end
118
+
119
+ def access
120
+ @last_accessed = Time.now
121
+ end
122
+
123
+ def forgettable?(threshold)
124
+ Time.now - @last_accessed > threshold * (1.0 / @detail_level)
125
+ end
126
+ end
127
+
128
+ class TemporalKnowledgeGraph
129
+ def initialize(forget_threshold: 30 * 24 * 60 * 60) # 30 days in seconds
130
+ @nodes = {}
131
+ @forget_threshold = forget_threshold
132
+ end
133
+
134
+ def add_node(node:)
135
+ @nodes[node.id] = node
136
+ end
137
+
138
+ def access_node(id:)
139
+ node = @nodes[id]
140
+ node.access if node
141
+ node
142
+ end
143
+
144
+ def forget_old_nodes
145
+ @nodes.delete_if do |id, node|
146
+ node.forgettable?(@forget_threshold)
147
+ end
148
+ end
149
+
150
+ def connect_nodes(from_id:, to_id:, relationship:)
151
+ from_node = @nodes[from_id]
152
+ to_node = @nodes[to_id]
153
+ from_node.connections[relationship] << to_node if from_node && to_node
154
+ end
155
+ end
156
+
157
+ # Usage
158
+ graph = TemporalKnowledgeGraph.new(forget_threshold: 60 * 60 * 24) # 1 day
159
+
160
+ node1 = KnowledgeNode.new(id: 1, content: "Science", detail_level: 1)
161
+ node2 = KnowledgeNode.new(id: 2, content: "Physics", detail_level: 2)
162
+ node3 = KnowledgeNode.new(id: 3, content: "Quantum Entanglement", detail_level: 3)
163
+
164
+ graph.add_node(node: node1)
165
+ graph.add_node(node: node2)
166
+ graph.add_node(node: node3)
167
+
168
+ graph.connect_nodes(from_id: 1, to_id: 2, relationship: :more_specific)
169
+ graph.connect_nodes(from_id: 2, to_id: 3, relationship: :more_specific)
170
+
171
+ # Simulate passage of time and node access
172
+ sleep(2)
173
+ graph.access_node(id: 1)
174
+ graph.access_node(id: 2)
175
+
176
+ sleep(2)
177
+ graph.forget_old_nodes
178
+ # At this point, node3 might be forgotten, while node1 and node2 are retained
179
+
180
+
181
+ ############################################
182
+ require "set"
183
+
184
+ class HTMNode
185
+ attr_reader :id, :content, :detail_level, :last_accessed, :access_count
186
+
187
+ def initialize(id:, content:, detail_level:)
188
+ @id = id
189
+ @content = content
190
+ @detail_level = detail_level
191
+ @last_accessed = Time.now
192
+ @access_count = 0
193
+ @connections = Set.new
194
+ end
195
+
196
+ def access
197
+ @last_accessed = Time.now
198
+ @access_count += 1
199
+ end
200
+
201
+ def add_connection(node)
202
+ @connections.add(node)
203
+ end
204
+
205
+ def relevance_score(current_time)
206
+ time_factor = 1.0 / (current_time - @last_accessed)
207
+ detail_factor = 1.0 / @detail_level
208
+ access_factor = Math.log(@access_count + 1)
209
+ time_factor * detail_factor * access_factor
210
+ end
211
+ end
212
+
213
+ class HTMRAG
214
+ def initialize(forget_threshold: 30 * 24 * 60 * 60) # 30 days in seconds
215
+ @nodes = {}
216
+ @forget_threshold = forget_threshold
217
+ end
218
+
219
+ def add_node(node)
220
+ @nodes[node.id] = node
221
+ end
222
+
223
+ def connect_nodes(from_id, to_id)
224
+ @nodes[from_id].add_connection(@nodes[to_id])
225
+ end
226
+
227
+ def forget_old_nodes
228
+ current_time = Time.now
229
+ @nodes.delete_if do |_, node|
230
+ current_time - node.last_accessed > @forget_threshold
231
+ end
232
+ end
233
+
234
+ def retrieve_context(query, max_tokens: 1000)
235
+ relevant_nodes = find_relevant_nodes(query)
236
+ construct_context(relevant_nodes, max_tokens)
237
+ end
238
+
239
+ private
240
+
241
+ def find_relevant_nodes(query)
242
+ # This is a placeholder for semantic search
243
+ # In a real implementation, you'd use embeddings or other NLP techniques
244
+ @nodes.values.sort_by { |node| -node.relevance_score(Time.now) }
245
+ end
246
+
247
+ def construct_context(nodes, max_tokens)
248
+ context = ""
249
+ token_count = 0
250
+
251
+ nodes.each do |node|
252
+ break if token_count >= max_tokens
253
+
254
+ node_content = node.content
255
+ node_tokens = node_content.split.size # Simple tokenization
256
+
257
+ if token_count + node_tokens <= max_tokens
258
+ context += node_content + " "
259
+ token_count += node_tokens
260
+ node.access
261
+ else
262
+ remaining_tokens = max_tokens - token_count
263
+ truncated_content = node_content.split[0...remaining_tokens].join(" ")
264
+ context += truncated_content + " "
265
+ break
266
+ end
267
+ end
268
+
269
+ context.strip
270
+ end
271
+ end
272
+
273
+ # Usage example
274
+ rag = HTMRAG.new
275
+
276
+ node1 = HTMNode.new(id: 1, content: "AI is a broad field of computer science.", detail_level: 1)
277
+ node2 = HTMNode.new(id: 2, content: "Machine Learning is a subset of AI focused on data-driven
278
+ algorithms.", detail_level: 2)
279
+ node3 = HTMNode.new(id: 3, content: "Neural networks are a type of machine learning model
280
+ inspired by biological neurons.", detail_level: 3)
281
+
282
+ rag.add_node(node1)
283
+ rag.add_node(node2)
284
+ rag.add_node(node3)
285
+
286
+ rag.connect_nodes(1, 2)
287
+ rag.connect_nodes(2, 3)
288
+
289
+ context = rag.retrieve_context("What is AI?", max_tokens: 50)
290
+ puts context
291
+
292
+
293
+ ############################################
294
+ class Proposition
295
+ attr_reader :id, :content
296
+ attr_accessor :next, :related
297
+
298
+ def initialize(id:, content:)
299
+ @id = id
300
+ @content = content
301
+ @next = nil
302
+ @related = []
303
+ end
304
+ end
305
+
306
+ class PropositionGraph
307
+ attr_reader :propositions
308
+
309
+ def initialize
310
+ @propositions = {}
311
+ end
312
+
313
+ def add_proposition(prop)
314
+ @propositions[prop.id] = prop
315
+ end
316
+
317
+ def connect(from_id:, to_id:, relationship: :next)
318
+ from_prop = @propositions[from_id]
319
+ to_prop = @propositions[to_id]
320
+ if relationship == :next
321
+ from_prop.next = to_prop
322
+ else
323
+ from_prop.related << to_prop
324
+ end
325
+ end
326
+
327
+ def similarity_score(other_graph)
328
+ sequence_similarity = calculate_sequence_similarity(other_graph)
329
+ structure_similarity = calculate_structure_similarity(other_graph)
330
+ (sequence_similarity + structure_similarity) / 2.0
331
+ end
332
+
333
+ private
334
+
335
+ def calculate_sequence_similarity(other_graph)
336
+ # Implement sequence comparison logic here
337
+ # This could involve comparing the 'next' chains of both graphs
338
+ # Return a score between 0 and 1
339
+ end
340
+
341
+ def calculate_structure_similarity(other_graph)
342
+ # Implement structure comparison logic here
343
+ # This could involve comparing the 'related' connections of both graphs
344
+ # Return a score between 0 and 1
345
+ end
346
+ end
347
+
348
+ class GraphBasedRAG
349
+ def initialize
350
+ @stored_graphs = []
351
+ end
352
+
353
+ def add_graph(graph)
354
+ @stored_graphs << graph
355
+ end
356
+
357
+ def retrieve_context(prompt_graph, top_n: 3)
358
+ scored_graphs = @stored_graphs.map do |graph|
359
+ {
360
+ graph: graph,
361
+ score: graph.similarity_score(prompt_graph),
362
+ }
363
+ end
364
+
365
+ top_graphs = scored_graphs.sort_by { |g| -g[:score] }.take(top_n)
366
+ construct_context(top_graphs)
367
+ end
368
+
369
+ private
370
+
371
+ def construct_context(top_graphs)
372
+ # Implement logic to construct context from top graphs
373
+ # This could involve extracting key propositions or summarizing the graphs
374
+ end
375
+ end
376
+
377
+ # Usage example
378
+ rag = GraphBasedRAG.new
379
+
380
+ # Create and add some stored graphs
381
+ graph1 = PropositionGraph.new
382
+ prop1 = Proposition.new(id: 1, content: "AI is a field of computer science")
383
+ prop2 = Proposition.new(id: 2, content: "Machine Learning is a subset of AI")
384
+ graph1.add_proposition(prop1)
385
+ graph1.add_proposition(prop2)
386
+ graph1.connect(from_id: 1, to_id: 2)
387
+ rag.add_graph(graph1)
388
+
389
+ # ... Add more graphs ...
390
+
391
+ # Create a graph from the prompt
392
+ prompt_graph = PropositionGraph.new
393
+ prompt_prop1 = Proposition.new(id: 1, content: "What is AI")
394
+ prompt_prop2 = Proposition.new(id: 2, content: "How does it relate to Machine Learning")
395
+ prompt_graph.add_proposition(prompt_prop1)
396
+ prompt_graph.add_proposition(prompt_prop2)
397
+ prompt_graph.connect(from_id: 1, to_id: 2)
398
+
399
+ # Retrieve context
400
+ context = rag.retrieve_context(prompt_graph)
401
+ puts context
402
+
403
+
404
+ ############################################
405
+ require "pg"
406
+
407
+ class GraphDatabase
408
+ def initialize(dbname:, user:, password:)
409
+ @conn = PG.connect(dbname: dbname, user: user, password: password)
410
+ @conn.exec("CREATE EXTENSION IF NOT EXISTS age")
411
+ @conn.exec("LOAD 'age'")
412
+ @conn.exec("SET search_path = ag_catalog, \"$user\", public")
413
+ end
414
+
415
+ def create_graph(name)
416
+ @conn.exec("SELECT create_graph('#{name}')")
417
+ end
418
+
419
+ def add_vertex(graph, properties)
420
+ props = properties.map { |k, v| "#{k}: '#{v}'" }.join(", ")
421
+ @conn.exec("SELECT * FROM cypher('#{graph}', $$ CREATE (:Proposition {#{props}}) $$) as (v
422
+ agtype)")
423
+ end
424
+
425
+ def add_edge(graph, from_id, to_id, relationship)
426
+ @conn.exec("SELECT * FROM cypher('#{graph}', $$ MATCH (a), (b) WHERE id(a) = #{from_id} AND
427
+ id(b) = #{to_id} CREATE (a)-[:#{relationship}]->(b) $$) as (e agtype)")
428
+ end
429
+
430
+ def query(graph, cypher)
431
+ result = @conn.exec("SELECT * FROM cypher('#{graph}', $$ #{cypher} $$) as (result agtype)")
432
+ result.map { |row| row["result"] }
433
+ end
434
+ end
435
+
436
+ # Usage
437
+ db = GraphDatabase.new(dbname: "your_db", user: "your_user", password: "your_password")
438
+ db.create_graph("knowledge_graph")
439
+ db.add_vertex("knowledge_graph", { content: "AI is a field of computer science", detail_level: 1 })
440
+ db.add_vertex("knowledge_graph", { content: "Machine Learning is a subset of AI", detail_level: 2 })
441
+ db.add_edge("knowledge_graph", 0, 1, "SPECIALIZES")
442
+
443
+ result = db.query("knowledge_graph", "MATCH (p:Proposition) RETURN p")
444
+ puts result
445
+
446
+
447
+ ############################################
448
+ class PropositionGraphDatabase
449
+ def initialize(dbname:, user:, password:)
450
+ @db = GraphDatabase.new(dbname: dbname, user: user, password: password)
451
+ @db.create_graph("proposition_graph")
452
+ end
453
+
454
+ def add_proposition(content:, detail_level:)
455
+ @db.add_vertex("proposition_graph", { content: content, detail_level: detail_level })
456
+ end
457
+
458
+ def connect_propositions(from_id:, to_id:, relationship: "NEXT")
459
+ @db.add_edge("proposition_graph", from_id, to_id, relationship)
460
+ end
461
+
462
+ def find_similar_graphs(prompt_graph)
463
+ # This is a simplified example. In practice, you'd need a more sophisticated
464
+ # algorithm to compare graph structures.
465
+ cypher = "" "
466
+ MATCH path = (start:Proposition)-[:NEXT*]->(end:Proposition)
467
+ WHERE NOT (end)-[:NEXT]->()
468
+ WITH path, nodes(path) AS props
469
+ RETURN path,
470
+ reduce(similarity = 0, p IN props |
471
+ similarity + CASE WHEN p.content CONTAINS '#{prompt_graph.first.content}' THEN 1 ELSE 0 END
472
+ ) AS similarity_score
473
+ ORDER BY similarity_score DESC
474
+ LIMIT 5
475
+ " ""
476
+ @db.query("proposition_graph", cypher)
477
+ end
478
+ end
479
+
480
+ # Usage
481
+ graph_db = PropositionGraphDatabase.new(dbname: "your_db", user: "your_user", password: "your_password")
482
+ graph_db.add_proposition(content: "AI is a field of computer science", detail_level: 1)
483
+ graph_db.add_proposition(content: "Machine Learning is a subset of AI", detail_level: 2)
484
+ graph_db.connect_propositions(from_id: 0, to_id: 1)
485
+
486
+ prompt_graph = [OpenStruct.new(content: "What is AI")]
487
+ similar_graphs = graph_db.find_similar_graphs(prompt_graph)
488
+ puts similar_graphs
489
+
490
+
491
+ ############################################
492
+ class PropositionGraphDatabase
493
+ def initialize(dbname:, user:, password:)
494
+ @db = GraphDatabase.new(dbname: dbname, user: user, password: password)
495
+ @db.create_graph("proposition_graph")
496
+ end
497
+
498
+ def add_proposition(content:, detail_level:)
499
+ @db.add_vertex("proposition_graph", { content: content, detail_level: detail_level })
500
+ end
501
+
502
+ def connect_propositions(from_id:, to_id:, relationship: "NEXT")
503
+ @db.add_edge("proposition_graph", from_id, to_id, relationship)
504
+ end
505
+
506
+ def find_similar_graphs(prompt_graph)
507
+ # This is a simplified example. In practice, you'd need a more sophisticated
508
+ # algorithm to compare graph structures.
509
+ cypher = "" "
510
+ MATCH path = (start:Proposition)-[:NEXT*]->(end:Proposition)
511
+ WHERE NOT (end)-[:NEXT]->()
512
+ WITH path, nodes(path) AS props
513
+ RETURN path,
514
+ reduce(similarity = 0, p IN props |
515
+ similarity + CASE WHEN p.content CONTAINS '#{prompt_graph.first.content}' THEN 1 ELSE 0 END
516
+ ) AS similarity_score
517
+ ORDER BY similarity_score DESC
518
+ LIMIT 5
519
+ " ""
520
+ @db.query("proposition_graph", cypher)
521
+ end
522
+ end
523
+
524
+ # Usage
525
+ graph_db = PropositionGraphDatabase.new(dbname: "your_db", user: "your_user", password: "your_password")
526
+ graph_db.add_proposition(content: "AI is a field of computer science", detail_level: 1)
527
+ graph_db.add_proposition(content: "Machine Learning is a subset of AI", detail_level: 2)
528
+ graph_db.connect_propositions(from_id: 0, to_id: 1)
529
+
530
+ prompt_graph = [OpenStruct.new(content: "What is AI")]
531
+ similar_graphs = graph_db.find_similar_graphs(prompt_graph)
532
+ puts similar_graphs
533
+
534
+
535
+ ############################################
536
+ require "openai"
537
+ require "json"
538
+
539
+ class KnowledgeGraphGenerator
540
+ def initialize(api_key)
541
+ @client = OpenAI::Client.new(access_token: api_key)
542
+ end
543
+
544
+ def generate_graph(text)
545
+ prompt = <<~PROMPT
546
+ Given the following paragraph, create a knowledge graph.
547
+ Output the result as a JSON object with the following structure:
548
+ {
549
+ "nodes": [
550
+ {"id": "unique_id", "label": "concept or entity", "type": "entity_type"}
551
+ ],
552
+ "edges": [
553
+ {"source": "source_id", "target": "target_id", "label": "relationship"}
554
+ ]
555
+ }
556
+
557
+ Paragraph:
558
+ #{text}
559
+
560
+ JSON Knowledge Graph:
561
+ PROMPT
562
+
563
+ response = @client.chat(
564
+ parameters: {
565
+ model: "gpt-4", # or "gpt-3.5-turbo" if you don't have GPT-4 access
566
+ messages: [{ role: "user", content: prompt }],
567
+ temperature: 0.7,
568
+ },
569
+ )
570
+
571
+ JSON.parse(response.dig("choices", 0, "message", "content"))
572
+ end
573
+ end
574
+
575
+ class KnowledgeGraph
576
+ attr_reader :nodes, :edges
577
+
578
+ def initialize(data)
579
+ @nodes = data["nodes"]
580
+ @edges = data["edges"]
581
+ end
582
+
583
+ def to_s
584
+ "Nodes:\n" + @nodes.map { |n| " #{n["id"]}: #{n["label"]} (#{n["type"]})" }.join("\n") +
585
+ "\nEdges:\n" + @edges.map { |e|
586
+ " #{e["source"]} -> #{e["target"]}: #{e["label"]}"
587
+ }.join("\n")
588
+ end
589
+ end
590
+
591
+ # Usage
592
+ generator = KnowledgeGraphGenerator.new("your-openai-api-key")
593
+
594
+ text = "Artificial Intelligence (AI) is a broad field of computer science focused on creating
595
+ intelligent machines that can perform tasks that typically require human intelligence. Machine
596
+ Learning, a subset of AI, uses statistical techniques to give computer systems the ability to
597
+ 'learn' from data, without being explicitly programmed. Deep Learning, a further
598
+ specialization of Machine Learning, uses neural networks with many layers (hence 'deep') to
599
+ analyze various factors of data."
600
+
601
+ graph_data = generator.generate_graph(text)
602
+ graph = KnowledgeGraph.new(graph_data)
603
+
604
+ puts graph
605
+
606
+
607
+ ############################################
608
+ require "json"
609
+
610
+ class KnowledgeGraph
611
+ attr_reader :nodes, :edges
612
+
613
+ def initialize(data)
614
+ @nodes = data["nodes"]
615
+ @edges = data["edges"]
616
+ end
617
+
618
+ def to_s
619
+ "Nodes:\n" + @nodes.map { |n| " #{n["id"]}: #{n["label"]} (#{n["type"]})" }.join("\n") +
620
+ "\nEdges:\n" + @edges.map { |e|
621
+ " #{e["source"]} -> #{e["target"]}: #{e["label"]}"
622
+ }.join("\n")
623
+ end
624
+ end
625
+
626
+ # Assuming the JSON is stored in a variable called 'json_data'
627
+ graph_data = JSON.parse(json_data)
628
+ graph = KnowledgeGraph.new(graph_data)
629
+
630
+ puts graph
631
+
632
+ pin "vis-network", to: "https://ga.jspm.io/npm:vis-network@9.1.6/standalone/esm/vis-network.js"
633
+
634
+
635
+ ############################################
636
+ # app/controllers/knowledge_graphs_controller.rb
637
+ class KnowledgeGraphsController < ApplicationController
638
+ def show
639
+ @graph_data = {
640
+ nodes: [
641
+ { id: 1, label: "Resident", group: "Person" },
642
+ { id: 2, label: "Bossier City", group: "Location" },
643
+ { id: 3, label: "Louisiana", group: "Location" },
644
+ { id: 4, label: "2021 Tahoe LS", group: "Vehicle" },
645
+ { id: 5, label: "Poor eyesight", group: "Condition" },
646
+ { id: 6, label: "Driving restriction", group: "Regulation" },
647
+ ],
648
+ edges: [
649
+ { from: 1, to: 2, label: "resides in" },
650
+ { from: 2, to: 3, label: "located in" },
651
+ { from: 1, to: 4, label: "owns" },
652
+ { from: 1, to: 5, label: "has condition" },
653
+ { from: 1, to: 6, label: "subject to" },
654
+ { from: 6, to: 4, label: "applies to" },
655
+ { from: 5, to: 6, label: "causes" },
656
+ ],
657
+ }
658
+ end
659
+ end
660
+
661
+ # config/routes.rb
662
+ Rails.application.routes.draw do
663
+ get "knowledge_graph", to: "knowledge_graphs#show"
664
+ # ... other routes ...
665
+ end
666
+
667
+ # app/controllers/knowledge_graphs_controller.rb
668
+ class KnowledgeGraphsController < ApplicationController
669
+ def new
670
+ @knowledge_graph = KnowledgeGraph.new
671
+ end
672
+
673
+ def create
674
+ @knowledge_graph = KnowledgeGraph.new(knowledge_graph_params)
675
+ if @knowledge_graph.save
676
+ redirect_to @knowledge_graph
677
+ else
678
+ render :new
679
+ end
680
+ end
681
+
682
+ def show
683
+ @knowledge_graph = KnowledgeGraph.find(params[:id])
684
+ @graph_data = JSON.parse(@knowledge_graph.graph_data)
685
+ end
686
+
687
+ private
688
+
689
+ def knowledge_graph_params
690
+ params.require(:knowledge_graph).permit(:input_text)
691
+ end
692
+ end
@@ -0,0 +1,13 @@
1
+ # Agent to Agent (a2a) Protocol
2
+
3
+ Google just pulically announted their A2A public protocol for inter-agent coordination and discovery. Its a pretty thick specification much heavier and more complete that what is being proposed here within the Agent99 reference implementation; however, it is at the highest levels consistent with a centralized well-known server, use of HTML for inter-agent communication payloads of JSON packages; and, of course, agents a hetro implementations from anywhere but having the one communication standard in common.
4
+
5
+ ## Introductory Blog Post
6
+
7
+ https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/
8
+
9
+ ## Complete Specification
10
+
11
+ It contains sample applications in python and JavaShit
12
+
13
+ https://github.com/google/A2A