elastro-client 1.3.44__tar.gz → 1.3.46__tar.gz

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 (134) hide show
  1. {elastro_client-1.3.44/elastro_client.egg-info → elastro_client-1.3.46}/PKG-INFO +1 -1
  2. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/__init__.py +1 -1
  3. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/cli.py +4 -0
  4. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/__init__.py +6 -0
  5. elastro_client-1.3.46/elastro/cli/commands/memory.py +163 -0
  6. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/telemetry.py +11 -0
  7. elastro_client-1.3.46/elastro/cli/commands/tools.py +146 -0
  8. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/rag/ast_parser.py +20 -0
  9. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/rag/ingestor.py +11 -2
  10. {elastro_client-1.3.44 → elastro_client-1.3.46/elastro_client.egg-info}/PKG-INFO +1 -1
  11. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro_client.egg-info/SOURCES.txt +2 -0
  12. {elastro_client-1.3.44 → elastro_client-1.3.46}/pyproject.toml +1 -1
  13. {elastro_client-1.3.44 → elastro_client-1.3.46}/.coveragerc +0 -0
  14. {elastro_client-1.3.44 → elastro_client-1.3.46}/LICENSE +0 -0
  15. {elastro_client-1.3.44 → elastro_client-1.3.46}/MANIFEST.in +0 -0
  16. {elastro_client-1.3.44 → elastro_client-1.3.46}/README.md +0 -0
  17. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/advanced_features.md +0 -0
  18. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/api_reference.md +0 -0
  19. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/cli_usage.md +0 -0
  20. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/commands_reference.md +0 -0
  21. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/getting_started.md +0 -0
  22. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/roadmap.md +0 -0
  23. {elastro_client-1.3.44 → elastro_client-1.3.46}/docs/troubleshooting.md +0 -0
  24. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/advanced/__init__.py +0 -0
  25. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/advanced/aggregations.py +0 -0
  26. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/advanced/query_builder.py +0 -0
  27. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/advanced/scroll.py +0 -0
  28. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/__init__.py +0 -0
  29. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/art.py +0 -0
  30. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/cluster.py +0 -0
  31. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/config.py +0 -0
  32. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/daemon.py +0 -0
  33. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/datastream.py +0 -0
  34. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/document.py +0 -0
  35. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/gui.py +0 -0
  36. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/ilm.py +0 -0
  37. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/index.py +0 -0
  38. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/index_recipes.py +0 -0
  39. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/ingest.py +0 -0
  40. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/ml.py +0 -0
  41. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/painless_commands.py +0 -0
  42. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/rag.py +0 -0
  43. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/script.py +0 -0
  44. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/security.py +0 -0
  45. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/snapshot.py +0 -0
  46. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/tasks.py +0 -0
  47. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/template.py +0 -0
  48. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/commands/utils.py +0 -0
  49. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/completion.py +0 -0
  50. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/cli/output.py +0 -0
  51. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/config/__init__.py +0 -0
  52. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/config/defaults.py +0 -0
  53. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/config/loader.py +0 -0
  54. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/__init__.py +0 -0
  55. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/client.py +0 -0
  56. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/daemon.py +0 -0
  57. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/datastream.py +0 -0
  58. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/document.py +0 -0
  59. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/document_bulk.py +0 -0
  60. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/errors.py +0 -0
  61. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/ilm.py +0 -0
  62. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/index.py +0 -0
  63. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/logger.py +0 -0
  64. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/query_builder.py +0 -0
  65. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/snapshot.py +0 -0
  66. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/core/validation.py +0 -0
  67. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/gui/assets/index-CeUjjtn-.css +0 -0
  68. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/gui/assets/index-DNdGuJvV.js +0 -0
  69. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/gui/elastro.svg +0 -0
  70. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/gui/favicon.ico +0 -0
  71. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/gui/index.html +0 -0
  72. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/gui/vite.svg +0 -0
  73. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/py.typed +0 -0
  74. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/server.py +0 -0
  75. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/utils/__init__.py +0 -0
  76. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/utils/aliases.py +0 -0
  77. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/utils/health.py +0 -0
  78. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/utils/snapshots.py +0 -0
  79. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro/utils/templates.py +0 -0
  80. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro_client.egg-info/dependency_links.txt +0 -0
  81. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro_client.egg-info/entry_points.txt +0 -0
  82. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro_client.egg-info/requires.txt +0 -0
  83. {elastro_client-1.3.44 → elastro_client-1.3.46}/elastro_client.egg-info/top_level.txt +0 -0
  84. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/client.py +0 -0
  85. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/config_usage.py +0 -0
  86. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/datastreams.py +0 -0
  87. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/debug_connection.py +0 -0
  88. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/document_operations.py +0 -0
  89. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/index_management.py +0 -0
  90. {elastro_client-1.3.44 → elastro_client-1.3.46}/examples/search.py +0 -0
  91. {elastro_client-1.3.44 → elastro_client-1.3.46}/pytest.ini +0 -0
  92. {elastro_client-1.3.44 → elastro_client-1.3.46}/requirements.txt +0 -0
  93. {elastro_client-1.3.44 → elastro_client-1.3.46}/setup.cfg +0 -0
  94. {elastro_client-1.3.44 → elastro_client-1.3.46}/setup.py +0 -0
  95. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/__init__.py +0 -0
  96. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/conftest.py +0 -0
  97. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/fixtures/__init__.py +0 -0
  98. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/fixtures/datastream_fixtures.py +0 -0
  99. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/fixtures/document_fixtures.py +0 -0
  100. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/fixtures/index_fixtures.py +0 -0
  101. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/__init__.py +0 -0
  102. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_aggregations_integration.py +0 -0
  103. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_client_integration.py +0 -0
  104. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_datastream_integration.py +0 -0
  105. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_docs_quickstart.py +0 -0
  106. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_document_integration.py +0 -0
  107. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_index_integration.py +0 -0
  108. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_query_builder_integration.py +0 -0
  109. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_scroll_integration.py +0 -0
  110. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/integration/test_workflow_integration.py +0 -0
  111. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/manual/test_es.py +0 -0
  112. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/__init__.py +0 -0
  113. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/advanced/__init__.py +0 -0
  114. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/advanced/test_aggregations.py +0 -0
  115. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/advanced/test_query_builder.py +0 -0
  116. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/advanced/test_scroll.py +0 -0
  117. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/config/__init__.py +0 -0
  118. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/config/test_defaults.py +0 -0
  119. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/config/test_loader.py +0 -0
  120. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/__init__.py +0 -0
  121. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_client.py +0 -0
  122. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_datastream.py +0 -0
  123. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_document.py +0 -0
  124. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_document_bulk.py +0 -0
  125. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_errors.py +0 -0
  126. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_index.py +0 -0
  127. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/core/test_validation.py +0 -0
  128. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/utils/__init__.py +0 -0
  129. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/utils/test_aliases.py +0 -0
  130. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/utils/test_health.py +0 -0
  131. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/utils/test_snapshots.py +0 -0
  132. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/unit/utils/test_templates.py +0 -0
  133. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/verify_api_actions.py +0 -0
  134. {elastro_client-1.3.44 → elastro_client-1.3.46}/tests/verify_cli_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elastro-client
3
- Version: 1.3.44
3
+ Version: 1.3.46
4
4
  Summary: A comprehensive Python library for Elasticsearch management with both programmatic and CLI interfaces
5
5
  Author: Austin Jorgensen
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ Elasticsearch Management Module.
4
4
  A module for managing Elasticsearch operations within a pipeline process.
5
5
  """
6
6
 
7
- __version__ = "1.3.44"
7
+ __version__ = "1.3.46"
8
8
 
9
9
  # Core component imports
10
10
  from elastro.core.client import ElasticsearchClient
@@ -109,6 +109,8 @@ from elastro.cli.commands.ml import ml_group
109
109
  from elastro.cli.commands.script import script_group
110
110
  from elastro.cli.commands.painless_commands import painless_group
111
111
  from elastro.cli.commands.telemetry import telemetry_group
112
+ from elastro.cli.commands.memory import memory_group
113
+ from elastro.cli.commands.tools import tools_group
112
114
 
113
115
  # Register Top-Level Groups
114
116
 
@@ -287,6 +289,8 @@ cli.add_command(ml_group)
287
289
  cli.add_command(script_group)
288
290
  cli.add_command(painless_group)
289
291
  cli.add_command(telemetry_group)
292
+ cli.add_command(memory_group)
293
+ cli.add_command(tools_group)
290
294
  cli.add_command(gui)
291
295
  cli.add_command(rag_group)
292
296
  cli.add_command(daemon_group)
@@ -41,6 +41,8 @@ from elastro.cli.commands.config import (
41
41
  from elastro.cli.commands.utils import health, templates, aliases
42
42
  from elastro.cli.commands.painless_commands import painless_group
43
43
  from elastro.cli.commands.telemetry import telemetry_group
44
+ from elastro.cli.commands.memory import memory_group
45
+ from elastro.cli.commands.tools import tools_group
44
46
 
45
47
  __all__ = [
46
48
  # Index commands
@@ -81,4 +83,8 @@ __all__ = [
81
83
  "painless_group",
82
84
  # Telemetry
83
85
  "telemetry_group",
86
+ # Agentic Memory
87
+ "memory_group",
88
+ # Tools Registry
89
+ "tools_group",
84
90
  ]
@@ -0,0 +1,163 @@
1
+ """
2
+ Memory command group for Elastro CLI.
3
+ """
4
+
5
+ import rich_click as click
6
+ from datetime import datetime, timezone
7
+
8
+ from elastro.core.client import ElasticsearchClient
9
+
10
+
11
+ @click.group(name="memory")
12
+ def memory_group() -> None:
13
+ """Manage semantic memory for agents."""
14
+ pass
15
+
16
+
17
+ @memory_group.command("ingest")
18
+ @click.argument("note_type", type=click.Choice(["strategic", "tactical"]))
19
+ @click.argument("subject")
20
+ @click.argument("content")
21
+ @click.option("--tags", default="", help="Comma-separated tags")
22
+ @click.pass_obj
23
+ def ingest_memory(
24
+ client: ElasticsearchClient,
25
+ note_type: str,
26
+ subject: str,
27
+ content: str,
28
+ tags: str,
29
+ ) -> None:
30
+ """
31
+ Ingest a semantic memory note for agent knowledge sharing.
32
+
33
+ NOTE_TYPE must be 'strategic' (telemetry/heuristics) or 'tactical' (handoffs).
34
+ """
35
+ index_name = "agent_semantic_memory"
36
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
37
+
38
+ payload = {
39
+ "timestamp": timestamp,
40
+ "note_type": note_type,
41
+ "subject": subject,
42
+ "content": content,
43
+ "tags": [t.strip() for t in tags.split(",")] if tags else [],
44
+ }
45
+
46
+ try:
47
+ response = client.client.index(index=index_name, document=payload)
48
+ click.secho(
49
+ f">> Memory ingested successfully. ID: {response.get('_id', 'unknown')}",
50
+ fg="green",
51
+ )
52
+ except Exception as e:
53
+ click.secho(f"Failed to ingest memory payload: {e}", fg="red", err=True)
54
+ import sys
55
+
56
+ sys.exit(1)
57
+
58
+
59
+ @memory_group.command("search")
60
+ @click.argument("query")
61
+ @click.option(
62
+ "--type",
63
+ "note_type",
64
+ type=click.Choice(["strategic", "tactical"]),
65
+ help="Filter by note type",
66
+ )
67
+ @click.option("--size", default=10, help="Number of results to return")
68
+ @click.pass_obj
69
+ def search_memory(
70
+ client: ElasticsearchClient,
71
+ query: str,
72
+ note_type: str,
73
+ size: int,
74
+ ) -> None:
75
+ """
76
+ Search semantic memory notes via vector/BM25 retrieval.
77
+ """
78
+ index_name = "agent_semantic_memory"
79
+
80
+ from typing import Dict, Any, List
81
+
82
+ bool_clause: Dict[str, List[Any]] = {
83
+ "must": [
84
+ {
85
+ "multi_match": {
86
+ "query": query,
87
+ "fields": ["subject^2", "content", "tags"],
88
+ }
89
+ }
90
+ ]
91
+ }
92
+
93
+ if note_type:
94
+ bool_clause["filter"] = [{"term": {"note_type": note_type}}]
95
+
96
+ search_body: Dict[str, Any] = {
97
+ "size": size,
98
+ "query": {"bool": bool_clause},
99
+ }
100
+
101
+ try:
102
+ response = client.client.search(index=index_name, body=search_body)
103
+ hits = response.get("hits", {}).get("hits", [])
104
+
105
+ click.secho(f"Found {len(hits)} memory notes:", fg="blue")
106
+ for hit in hits:
107
+ if not isinstance(hit, dict):
108
+ continue
109
+ source = hit.get("_source", {})
110
+ click.echo(
111
+ f"\n[{source.get('note_type', 'unknown').upper()}] {source.get('subject', 'Untitled')} ({hit.get('_id', '')})"
112
+ )
113
+ click.echo(f" {source.get('content', '')}")
114
+ if source.get("tags"):
115
+ click.echo(f" Tags: {', '.join(source['tags'])}")
116
+
117
+ except Exception as e:
118
+ click.secho(f"Search failed: {e}", fg="red", err=True)
119
+ import sys
120
+
121
+ sys.exit(1)
122
+
123
+
124
+ @memory_group.command("prune")
125
+ @click.option("--days", default=7, help="Number of days to retain tactical notes")
126
+ @click.pass_obj
127
+ def prune_memory(
128
+ client: ElasticsearchClient,
129
+ days: int,
130
+ ) -> None:
131
+ """
132
+ Prune 'tactical' memory notes older than the specified threshold.
133
+ """
134
+ index_name = "agent_semantic_memory"
135
+
136
+ from datetime import datetime, timezone, timedelta
137
+
138
+ cutoff = datetime.now(timezone.utc) - timedelta(days=days)
139
+ cutoff_str = cutoff.strftime("%Y-%m-%dT%H:%M:%SZ")
140
+
141
+ delete_query = {
142
+ "query": {
143
+ "bool": {
144
+ "must": [
145
+ {"term": {"note_type": "tactical"}},
146
+ {"range": {"timestamp": {"lt": cutoff_str}}},
147
+ ]
148
+ }
149
+ }
150
+ }
151
+
152
+ try:
153
+ response = client.client.delete_by_query(index=index_name, body=delete_query)
154
+ deleted = response.get("deleted", 0)
155
+ click.secho(
156
+ f">> Pruned {deleted} tactical memory notes older than {days} days.",
157
+ fg="green",
158
+ )
159
+ except Exception as e:
160
+ click.secho(f"Failed to prune memory notes: {e}", fg="red", err=True)
161
+ import sys
162
+
163
+ sys.exit(1)
@@ -45,6 +45,11 @@ def telemetry_group() -> None:
45
45
  help="Comma-separated list of executed tools",
46
46
  )
47
47
  @click.option("--rollback-count", type=int, default=0, help="Explicit undo rate")
48
+ @click.option("--diff-drift", type=float, default=0.0, help="Diff Drift Ratio")
49
+ @click.option(
50
+ "--fallback-rate", type=float, default=0.0, help="Deterministic Fallback Rate"
51
+ )
52
+ @click.option("--complexity", type=float, default=0.0, help="Complexity Score")
48
53
  @click.pass_obj
49
54
  def ingest_telemetry(
50
55
  client: ElasticsearchClient,
@@ -68,6 +73,9 @@ def ingest_telemetry(
68
73
  llm_model: str,
69
74
  tools_invoked: str,
70
75
  rollback_count: int,
76
+ diff_drift: float,
77
+ fallback_rate: float,
78
+ complexity: float,
71
79
  ) -> None:
72
80
  """
73
81
  Ingest standardized session telemetry into the deep analytics index.
@@ -103,6 +111,9 @@ def ingest_telemetry(
103
111
  [t.strip() for t in tools_invoked.split(",")] if tools_invoked else []
104
112
  ),
105
113
  "rollback_undo_count": rollback_count,
114
+ "diff_drift_ratio": diff_drift,
115
+ "deterministic_fallback_rate": fallback_rate,
116
+ "complexity_score": complexity,
106
117
  }
107
118
 
108
119
  try:
@@ -0,0 +1,146 @@
1
+ """
2
+ Tools registry command group for Elastro CLI.
3
+ """
4
+
5
+ import rich_click as click
6
+ from datetime import datetime, timezone
7
+
8
+ from elastro.core.client import ElasticsearchClient
9
+
10
+
11
+ @click.group(name="tools")
12
+ def tools_group() -> None:
13
+ """Manage the Custom Agentic Toolchain registry."""
14
+ pass
15
+
16
+
17
+ @tools_group.command("register")
18
+ @click.argument("tool_name")
19
+ @click.argument("file_path")
20
+ @click.argument("purpose")
21
+ @click.option(
22
+ "--parameters", default="", help="JSON string or comma-separated list of params"
23
+ )
24
+ @click.pass_obj
25
+ def register_tool(
26
+ client: ElasticsearchClient,
27
+ tool_name: str,
28
+ file_path: str,
29
+ purpose: str,
30
+ parameters: str,
31
+ ) -> None:
32
+ """
33
+ Register a custom pipeline script or CLI into the tools registry.
34
+ """
35
+ index_name = "flow_tools"
36
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
37
+
38
+ import os
39
+ import hashlib
40
+
41
+ file_hash = "unknown"
42
+ if os.path.isfile(file_path):
43
+ with open(file_path, "rb") as f:
44
+ file_hash = hashlib.sha256(f.read()).hexdigest()
45
+ else:
46
+ click.secho(
47
+ f"Warning: File '{file_path}' not found at registration time.", fg="yellow"
48
+ )
49
+
50
+ payload = {
51
+ "timestamp": timestamp,
52
+ "tool_name": tool_name,
53
+ "file_path": file_path,
54
+ "purpose": purpose,
55
+ "parameters": parameters,
56
+ "file_hash": file_hash,
57
+ }
58
+
59
+ try:
60
+ response = client.client.index(index=index_name, id=tool_name, document=payload)
61
+ click.secho(
62
+ f">> Tool '{tool_name}' registered successfully.",
63
+ fg="green",
64
+ )
65
+ except Exception as e:
66
+ click.secho(f"Failed to register tool payload: {e}", fg="red", err=True)
67
+ import sys
68
+
69
+ sys.exit(1)
70
+
71
+
72
+ @tools_group.command("search")
73
+ @click.argument("query")
74
+ @click.option("--size", default=10, help="Number of results to return")
75
+ @click.pass_obj
76
+ def search_tools(
77
+ client: ElasticsearchClient,
78
+ query: str,
79
+ size: int,
80
+ ) -> None:
81
+ """
82
+ Search the flow_tools custom tool registry.
83
+ """
84
+ index_name = "flow_tools"
85
+
86
+ search_body = {
87
+ "size": size,
88
+ "query": {
89
+ "multi_match": {
90
+ "query": query,
91
+ "fields": ["tool_name^3", "purpose^2", "parameters"],
92
+ }
93
+ },
94
+ }
95
+
96
+ try:
97
+ response = client.client.search(index=index_name, body=search_body)
98
+ hits = response.get("hits", {}).get("hits", [])
99
+
100
+ click.secho(f"Found {len(hits)} registered tools:", fg="blue")
101
+ for hit in hits:
102
+ if not isinstance(hit, dict):
103
+ continue
104
+ source = hit.get("_source", {})
105
+ tool_name = source.get("tool_name", "Unknown")
106
+ file_path = source.get("file_path", "unknown")
107
+ indexed_hash = source.get("file_hash", "unknown")
108
+
109
+ click.echo(f"\n[TOOL] {tool_name}")
110
+ click.echo(f" Path: {file_path}")
111
+ click.echo(f" Purpose: {source.get('purpose', '')}")
112
+ click.echo(f" Parameters: {source.get('parameters', '')}")
113
+
114
+ import os
115
+ import hashlib
116
+
117
+ if file_path != "unknown" and os.path.isfile(file_path):
118
+ with open(file_path, "rb") as f:
119
+ current_hash = hashlib.sha256(f.read()).hexdigest()
120
+
121
+ if indexed_hash == "unknown":
122
+ click.secho(
123
+ " Hash Status: [UNTRACKED] No index hash recorded.",
124
+ fg="yellow",
125
+ )
126
+ elif current_hash != indexed_hash:
127
+ click.secho(
128
+ " Hash Status: [STALE] Local file modified since registration!",
129
+ fg="red",
130
+ bold=True,
131
+ )
132
+ else:
133
+ click.secho(
134
+ " Hash Status: [VERIFIED] Local file matches index exact.",
135
+ fg="green",
136
+ )
137
+ else:
138
+ click.secho(
139
+ " Hash Status: [MISSING] File not found on disk.", fg="red"
140
+ )
141
+
142
+ except Exception as e:
143
+ click.secho(f"Search failed: {e}", fg="red", err=True)
144
+ import sys
145
+
146
+ sys.exit(1)
@@ -56,6 +56,8 @@ class ASTParser:
56
56
  return "typescript"
57
57
  elif ext == ".vue":
58
58
  return "vue"
59
+ elif ext == ".md":
60
+ return "markdown"
59
61
  return "unsupported"
60
62
 
61
63
  def parse_file(self, file_path: str, content: str) -> List[Dict[str, Any]]:
@@ -65,6 +67,24 @@ class ASTParser:
65
67
  ext = os.path.splitext(file_path)[1]
66
68
  lang = self._determine_language(ext)
67
69
 
70
+ if lang == "markdown":
71
+ import re
72
+
73
+ # Extract declarative Node-IDs like `repo:path/to/file.py::0` or `path/to/file.py`
74
+ node_refs = re.findall(
75
+ r"`([a-zA-Z0-9_\-\.]+:[a-zA-Z0-9_\-\.\/]+::\d+)`", content
76
+ )
77
+ file_refs = re.findall(r"`([a-zA-Z0-9_\-\.\/]+\.[a-zA-Z]{2,4})`", content)
78
+ return [
79
+ {
80
+ "chunk_type": "knowledge_item",
81
+ "name": os.path.basename(file_path),
82
+ "content": content,
83
+ "functions_defined": list(set(node_refs)),
84
+ "functions_called": list(set(file_refs)),
85
+ }
86
+ ]
87
+
68
88
  if lang not in self.parsers:
69
89
  return [
70
90
  {
@@ -23,8 +23,17 @@ class GraphRAGManager:
23
23
  self.index_name = index_name
24
24
  self.ast_parser = ASTParser()
25
25
 
26
- # We explicitly target the agent's core polyglot languages
27
- self.supported_extensions = {".py", ".go", ".vue", ".js", ".ts", ".jsx", ".tsx"}
26
+ # We explicitly target the agent's core polyglot languages + Markdown for KI Bridging
27
+ self.supported_extensions = {
28
+ ".py",
29
+ ".go",
30
+ ".vue",
31
+ ".js",
32
+ ".ts",
33
+ ".jsx",
34
+ ".tsx",
35
+ ".md",
36
+ }
28
37
 
29
38
  # Prevent indexing binary data, large dependency folders, or generated outputs
30
39
  self.ignore_dirs = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elastro-client
3
- Version: 1.3.44
3
+ Version: 1.3.46
4
4
  Summary: A comprehensive Python library for Elasticsearch management with both programmatic and CLI interfaces
5
5
  Author: Austin Jorgensen
6
6
  License-Expression: MIT
@@ -36,6 +36,7 @@ elastro/cli/commands/ilm.py
36
36
  elastro/cli/commands/index.py
37
37
  elastro/cli/commands/index_recipes.py
38
38
  elastro/cli/commands/ingest.py
39
+ elastro/cli/commands/memory.py
39
40
  elastro/cli/commands/ml.py
40
41
  elastro/cli/commands/painless_commands.py
41
42
  elastro/cli/commands/rag.py
@@ -45,6 +46,7 @@ elastro/cli/commands/snapshot.py
45
46
  elastro/cli/commands/tasks.py
46
47
  elastro/cli/commands/telemetry.py
47
48
  elastro/cli/commands/template.py
49
+ elastro/cli/commands/tools.py
48
50
  elastro/cli/commands/utils.py
49
51
  elastro/config/__init__.py
50
52
  elastro/config/defaults.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "elastro-client"
7
- version = "1.3.44"
7
+ version = "1.3.46"
8
8
  description = "A comprehensive Python library for Elasticsearch management with both programmatic and CLI interfaces"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9,<3.14"
File without changes