agent_os_kernel 3.1.0__py3-none-any.whl

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 (337) hide show
  1. agent_control_plane/__init__.py +662 -0
  2. agent_control_plane/a2a_adapter.py +543 -0
  3. agent_control_plane/adapter.py +417 -0
  4. agent_control_plane/agent_hibernation.py +394 -0
  5. agent_control_plane/agent_kernel.py +470 -0
  6. agent_control_plane/compliance.py +720 -0
  7. agent_control_plane/constraint_graphs.py +478 -0
  8. agent_control_plane/control_plane.py +854 -0
  9. agent_control_plane/example_executors.py +195 -0
  10. agent_control_plane/execution_engine.py +231 -0
  11. agent_control_plane/flight_recorder.py +846 -0
  12. agent_control_plane/governance_layer.py +435 -0
  13. agent_control_plane/hf_utils.py +563 -0
  14. agent_control_plane/interfaces/__init__.py +55 -0
  15. agent_control_plane/interfaces/kernel_interface.py +361 -0
  16. agent_control_plane/interfaces/plugin_interface.py +497 -0
  17. agent_control_plane/interfaces/protocol_interfaces.py +387 -0
  18. agent_control_plane/kernel_space.py +1009 -0
  19. agent_control_plane/langchain_adapter.py +424 -0
  20. agent_control_plane/lifecycle.py +3113 -0
  21. agent_control_plane/mcp_adapter.py +653 -0
  22. agent_control_plane/ml_safety.py +563 -0
  23. agent_control_plane/multimodal.py +727 -0
  24. agent_control_plane/mute_agent.py +422 -0
  25. agent_control_plane/observability.py +787 -0
  26. agent_control_plane/orchestrator.py +482 -0
  27. agent_control_plane/plugin_registry.py +750 -0
  28. agent_control_plane/policy_engine.py +954 -0
  29. agent_control_plane/process_isolation.py +777 -0
  30. agent_control_plane/shadow_mode.py +310 -0
  31. agent_control_plane/signals.py +493 -0
  32. agent_control_plane/supervisor_agents.py +430 -0
  33. agent_control_plane/time_travel_debugger.py +557 -0
  34. agent_control_plane/tool_registry.py +452 -0
  35. agent_control_plane/vfs.py +697 -0
  36. agent_kernel/__init__.py +69 -0
  37. agent_kernel/analyzer.py +435 -0
  38. agent_kernel/auditor.py +36 -0
  39. agent_kernel/completeness_auditor.py +237 -0
  40. agent_kernel/detector.py +203 -0
  41. agent_kernel/kernel.py +744 -0
  42. agent_kernel/memory_manager.py +85 -0
  43. agent_kernel/models.py +374 -0
  44. agent_kernel/nudge_mechanism.py +263 -0
  45. agent_kernel/outcome_analyzer.py +338 -0
  46. agent_kernel/patcher.py +582 -0
  47. agent_kernel/semantic_analyzer.py +316 -0
  48. agent_kernel/semantic_purge.py +349 -0
  49. agent_kernel/simulator.py +449 -0
  50. agent_kernel/teacher.py +85 -0
  51. agent_kernel/triage.py +152 -0
  52. agent_os/__init__.py +409 -0
  53. agent_os/_adversarial_impl.py +200 -0
  54. agent_os/_circuit_breaker_impl.py +232 -0
  55. agent_os/_mcp_metrics.py +193 -0
  56. agent_os/adversarial.py +20 -0
  57. agent_os/agents_compat.py +490 -0
  58. agent_os/audit_logger.py +135 -0
  59. agent_os/base_agent.py +651 -0
  60. agent_os/circuit_breaker.py +34 -0
  61. agent_os/cli/__init__.py +659 -0
  62. agent_os/cli/cmd_audit.py +128 -0
  63. agent_os/cli/cmd_init.py +152 -0
  64. agent_os/cli/cmd_policy.py +41 -0
  65. agent_os/cli/cmd_policy_gen.py +180 -0
  66. agent_os/cli/cmd_validate.py +258 -0
  67. agent_os/cli/mcp_scan.py +265 -0
  68. agent_os/cli/output.py +192 -0
  69. agent_os/cli/policy_checker.py +330 -0
  70. agent_os/compat.py +74 -0
  71. agent_os/constraint_graph.py +234 -0
  72. agent_os/content_governance.py +140 -0
  73. agent_os/context_budget.py +305 -0
  74. agent_os/credential_redactor.py +224 -0
  75. agent_os/diff_policy.py +89 -0
  76. agent_os/egress_policy.py +159 -0
  77. agent_os/escalation.py +276 -0
  78. agent_os/event_bus.py +124 -0
  79. agent_os/exceptions.py +180 -0
  80. agent_os/execution_context_policy.py +141 -0
  81. agent_os/github_enterprise.py +96 -0
  82. agent_os/health.py +20 -0
  83. agent_os/integrations/__init__.py +279 -0
  84. agent_os/integrations/a2a_adapter.py +279 -0
  85. agent_os/integrations/agent_lightning/__init__.py +30 -0
  86. agent_os/integrations/anthropic_adapter.py +420 -0
  87. agent_os/integrations/autogen_adapter.py +620 -0
  88. agent_os/integrations/base.py +1137 -0
  89. agent_os/integrations/compat.py +229 -0
  90. agent_os/integrations/config.py +98 -0
  91. agent_os/integrations/conversation_guardian.py +957 -0
  92. agent_os/integrations/crewai_adapter.py +467 -0
  93. agent_os/integrations/drift_detector.py +425 -0
  94. agent_os/integrations/dry_run.py +124 -0
  95. agent_os/integrations/escalation.py +582 -0
  96. agent_os/integrations/gemini_adapter.py +364 -0
  97. agent_os/integrations/google_adk_adapter.py +633 -0
  98. agent_os/integrations/guardrails_adapter.py +394 -0
  99. agent_os/integrations/health.py +197 -0
  100. agent_os/integrations/langchain_adapter.py +654 -0
  101. agent_os/integrations/llamafirewall.py +343 -0
  102. agent_os/integrations/llamaindex_adapter.py +188 -0
  103. agent_os/integrations/logging.py +191 -0
  104. agent_os/integrations/maf_adapter.py +631 -0
  105. agent_os/integrations/mistral_adapter.py +365 -0
  106. agent_os/integrations/openai_adapter.py +816 -0
  107. agent_os/integrations/openai_agents_sdk.py +406 -0
  108. agent_os/integrations/policy_compose.py +171 -0
  109. agent_os/integrations/profiling.py +144 -0
  110. agent_os/integrations/pydantic_ai_adapter.py +420 -0
  111. agent_os/integrations/rate_limiter.py +130 -0
  112. agent_os/integrations/rbac.py +143 -0
  113. agent_os/integrations/registry.py +113 -0
  114. agent_os/integrations/scope_guard.py +303 -0
  115. agent_os/integrations/semantic_kernel_adapter.py +769 -0
  116. agent_os/integrations/smolagents_adapter.py +629 -0
  117. agent_os/integrations/templates.py +178 -0
  118. agent_os/integrations/token_budget.py +134 -0
  119. agent_os/integrations/tool_aliases.py +190 -0
  120. agent_os/integrations/webhooks.py +177 -0
  121. agent_os/lite.py +208 -0
  122. agent_os/mcp_gateway.py +385 -0
  123. agent_os/mcp_message_signer.py +273 -0
  124. agent_os/mcp_protocols.py +161 -0
  125. agent_os/mcp_response_scanner.py +232 -0
  126. agent_os/mcp_security.py +924 -0
  127. agent_os/mcp_session_auth.py +231 -0
  128. agent_os/mcp_sliding_rate_limiter.py +184 -0
  129. agent_os/memory_guard.py +409 -0
  130. agent_os/metrics.py +134 -0
  131. agent_os/mute.py +428 -0
  132. agent_os/mute_agent.py +209 -0
  133. agent_os/policies/__init__.py +77 -0
  134. agent_os/policies/async_evaluator.py +275 -0
  135. agent_os/policies/backends.py +670 -0
  136. agent_os/policies/bridge.py +169 -0
  137. agent_os/policies/budget.py +85 -0
  138. agent_os/policies/cli.py +294 -0
  139. agent_os/policies/conflict_resolution.py +270 -0
  140. agent_os/policies/data_classification.py +252 -0
  141. agent_os/policies/evaluator.py +239 -0
  142. agent_os/policies/policy_schema.json +228 -0
  143. agent_os/policies/rate_limiting.py +145 -0
  144. agent_os/policies/schema.py +115 -0
  145. agent_os/policies/shared.py +331 -0
  146. agent_os/prompt_injection.py +694 -0
  147. agent_os/providers.py +182 -0
  148. agent_os/py.typed +0 -0
  149. agent_os/retry.py +81 -0
  150. agent_os/reversibility.py +251 -0
  151. agent_os/sandbox.py +432 -0
  152. agent_os/sandbox_provider.py +140 -0
  153. agent_os/secure_codegen.py +525 -0
  154. agent_os/security_skills.py +538 -0
  155. agent_os/semantic_policy.py +422 -0
  156. agent_os/server/__init__.py +15 -0
  157. agent_os/server/__main__.py +25 -0
  158. agent_os/server/app.py +277 -0
  159. agent_os/server/models.py +104 -0
  160. agent_os/shift_left_metrics.py +130 -0
  161. agent_os/stateless.py +742 -0
  162. agent_os/supervisor.py +148 -0
  163. agent_os/task_outcome.py +148 -0
  164. agent_os/transparency.py +181 -0
  165. agent_os/trust_root.py +128 -0
  166. agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
  167. agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
  168. agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
  169. agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
  170. agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
  171. agent_os_observability/__init__.py +27 -0
  172. agent_os_observability/dashboards.py +898 -0
  173. agent_os_observability/metrics.py +398 -0
  174. agent_os_observability/server.py +223 -0
  175. agent_os_observability/tracer.py +232 -0
  176. agent_primitives/__init__.py +24 -0
  177. agent_primitives/failures.py +84 -0
  178. agent_primitives/py.typed +0 -0
  179. amb_core/__init__.py +177 -0
  180. amb_core/adapters/__init__.py +57 -0
  181. amb_core/adapters/aws_sqs_broker.py +376 -0
  182. amb_core/adapters/azure_servicebus_broker.py +340 -0
  183. amb_core/adapters/kafka_broker.py +260 -0
  184. amb_core/adapters/nats_broker.py +285 -0
  185. amb_core/adapters/rabbitmq_broker.py +235 -0
  186. amb_core/adapters/redis_broker.py +262 -0
  187. amb_core/broker.py +145 -0
  188. amb_core/bus.py +481 -0
  189. amb_core/cloudevents.py +509 -0
  190. amb_core/dlq.py +345 -0
  191. amb_core/hf_utils.py +536 -0
  192. amb_core/memory_broker.py +410 -0
  193. amb_core/models.py +141 -0
  194. amb_core/persistence.py +529 -0
  195. amb_core/schema.py +294 -0
  196. amb_core/tracing.py +358 -0
  197. atr/__init__.py +640 -0
  198. atr/access.py +348 -0
  199. atr/composition.py +645 -0
  200. atr/decorator.py +357 -0
  201. atr/executor.py +384 -0
  202. atr/health.py +557 -0
  203. atr/hf_utils.py +449 -0
  204. atr/injection.py +422 -0
  205. atr/metrics.py +440 -0
  206. atr/policies.py +403 -0
  207. atr/py.typed +2 -0
  208. atr/registry.py +452 -0
  209. atr/schema.py +480 -0
  210. atr/tools/safe/__init__.py +75 -0
  211. atr/tools/safe/calculator.py +467 -0
  212. atr/tools/safe/datetime_tool.py +443 -0
  213. atr/tools/safe/file_reader.py +402 -0
  214. atr/tools/safe/http_client.py +316 -0
  215. atr/tools/safe/json_parser.py +374 -0
  216. atr/tools/safe/text_tool.py +537 -0
  217. atr/tools/safe/toolkit.py +175 -0
  218. caas/__init__.py +162 -0
  219. caas/api/__init__.py +7 -0
  220. caas/api/server.py +1328 -0
  221. caas/caching.py +834 -0
  222. caas/cli.py +210 -0
  223. caas/conversation.py +223 -0
  224. caas/decay.py +72 -0
  225. caas/detection/__init__.py +9 -0
  226. caas/detection/detector.py +238 -0
  227. caas/enrichment.py +130 -0
  228. caas/gateway/__init__.py +27 -0
  229. caas/gateway/trust_gateway.py +474 -0
  230. caas/hf_utils.py +479 -0
  231. caas/ingestion/__init__.py +23 -0
  232. caas/ingestion/processors.py +253 -0
  233. caas/ingestion/structure_parser.py +188 -0
  234. caas/models.py +356 -0
  235. caas/pragmatic_truth.py +444 -0
  236. caas/routing/__init__.py +10 -0
  237. caas/routing/heuristic_router.py +58 -0
  238. caas/storage/__init__.py +9 -0
  239. caas/storage/store.py +389 -0
  240. caas/triad.py +213 -0
  241. caas/tuning/__init__.py +9 -0
  242. caas/tuning/tuner.py +329 -0
  243. caas/vfs/__init__.py +14 -0
  244. caas/vfs/filesystem.py +452 -0
  245. cmvk/__init__.py +218 -0
  246. cmvk/audit.py +402 -0
  247. cmvk/benchmarks.py +478 -0
  248. cmvk/constitutional.py +904 -0
  249. cmvk/hf_utils.py +301 -0
  250. cmvk/metrics.py +473 -0
  251. cmvk/profiles.py +300 -0
  252. cmvk/py.typed +0 -0
  253. cmvk/types.py +12 -0
  254. cmvk/verification.py +956 -0
  255. emk/__init__.py +89 -0
  256. emk/causal.py +352 -0
  257. emk/hf_utils.py +421 -0
  258. emk/indexer.py +83 -0
  259. emk/py.typed +0 -0
  260. emk/schema.py +204 -0
  261. emk/sleep_cycle.py +347 -0
  262. emk/store.py +281 -0
  263. iatp/__init__.py +166 -0
  264. iatp/attestation.py +461 -0
  265. iatp/cli.py +317 -0
  266. iatp/hf_utils.py +472 -0
  267. iatp/ipc_pipes.py +580 -0
  268. iatp/main.py +412 -0
  269. iatp/models/__init__.py +447 -0
  270. iatp/policy_engine.py +337 -0
  271. iatp/py.typed +2 -0
  272. iatp/recovery.py +321 -0
  273. iatp/security/__init__.py +270 -0
  274. iatp/sidecar/__init__.py +519 -0
  275. iatp/telemetry/__init__.py +164 -0
  276. iatp/tests/__init__.py +1 -0
  277. iatp/tests/test_attestation.py +370 -0
  278. iatp/tests/test_cli.py +131 -0
  279. iatp/tests/test_ed25519_attestation.py +211 -0
  280. iatp/tests/test_models.py +130 -0
  281. iatp/tests/test_policy_engine.py +347 -0
  282. iatp/tests/test_recovery.py +281 -0
  283. iatp/tests/test_security.py +222 -0
  284. iatp/tests/test_sidecar.py +167 -0
  285. iatp/tests/test_telemetry.py +175 -0
  286. mcp_kernel_server/__init__.py +28 -0
  287. mcp_kernel_server/cli.py +274 -0
  288. mcp_kernel_server/resources.py +217 -0
  289. mcp_kernel_server/server.py +564 -0
  290. mcp_kernel_server/tools.py +1174 -0
  291. mute_agent/__init__.py +68 -0
  292. mute_agent/core/__init__.py +1 -0
  293. mute_agent/core/execution_agent.py +166 -0
  294. mute_agent/core/handshake_protocol.py +201 -0
  295. mute_agent/core/reasoning_agent.py +238 -0
  296. mute_agent/knowledge_graph/__init__.py +1 -0
  297. mute_agent/knowledge_graph/graph_elements.py +65 -0
  298. mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
  299. mute_agent/knowledge_graph/subgraph.py +224 -0
  300. mute_agent/listener/__init__.py +43 -0
  301. mute_agent/listener/adapters/__init__.py +31 -0
  302. mute_agent/listener/adapters/base_adapter.py +189 -0
  303. mute_agent/listener/adapters/caas_adapter.py +344 -0
  304. mute_agent/listener/adapters/control_plane_adapter.py +436 -0
  305. mute_agent/listener/adapters/iatp_adapter.py +332 -0
  306. mute_agent/listener/adapters/scak_adapter.py +251 -0
  307. mute_agent/listener/listener.py +610 -0
  308. mute_agent/listener/state_observer.py +436 -0
  309. mute_agent/listener/threshold_config.py +313 -0
  310. mute_agent/super_system/__init__.py +1 -0
  311. mute_agent/super_system/router.py +204 -0
  312. mute_agent/visualization/__init__.py +10 -0
  313. mute_agent/visualization/graph_debugger.py +502 -0
  314. nexus/README.md +60 -0
  315. nexus/__init__.py +51 -0
  316. nexus/arbiter.py +359 -0
  317. nexus/client.py +466 -0
  318. nexus/dmz.py +444 -0
  319. nexus/escrow.py +430 -0
  320. nexus/exceptions.py +286 -0
  321. nexus/pyproject.toml +36 -0
  322. nexus/registry.py +393 -0
  323. nexus/reputation.py +425 -0
  324. nexus/schemas/__init__.py +51 -0
  325. nexus/schemas/compliance.py +276 -0
  326. nexus/schemas/escrow.py +251 -0
  327. nexus/schemas/manifest.py +225 -0
  328. nexus/schemas/receipt.py +208 -0
  329. nexus/tests/__init__.py +0 -0
  330. nexus/tests/conftest.py +146 -0
  331. nexus/tests/test_arbiter.py +192 -0
  332. nexus/tests/test_dmz.py +194 -0
  333. nexus/tests/test_escrow.py +276 -0
  334. nexus/tests/test_exceptions.py +225 -0
  335. nexus/tests/test_registry.py +232 -0
  336. nexus/tests/test_reputation.py +328 -0
  337. nexus/tests/test_schemas.py +295 -0
caas/cli.py ADDED
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright (c) Microsoft Corporation.
3
+ # Licensed under the MIT License.
4
+ """
5
+ Command-line interface for Context-as-a-Service.
6
+ """
7
+
8
+ import sys
9
+ import json
10
+ from pathlib import Path
11
+
12
+ from caas.models import ContentFormat
13
+ from caas.ingestion import ProcessorFactory
14
+ from caas.detection import DocumentTypeDetector, StructureAnalyzer
15
+ from caas.tuning import WeightTuner
16
+ from caas.storage import DocumentStore, ContextExtractor
17
+
18
+
19
+ def main():
20
+ """Main CLI entry point."""
21
+ if len(sys.argv) < 2:
22
+ print_usage()
23
+ return
24
+
25
+ command = sys.argv[1]
26
+
27
+ if command == "ingest":
28
+ ingest_command()
29
+ elif command == "analyze":
30
+ analyze_command()
31
+ elif command == "context":
32
+ context_command()
33
+ elif command == "list":
34
+ list_command()
35
+ else:
36
+ print(f"Unknown command: {command}")
37
+ print_usage()
38
+
39
+
40
+ def print_usage():
41
+ """Print CLI usage information."""
42
+ print("""
43
+ Context-as-a-Service CLI
44
+
45
+ Usage:
46
+ caas ingest <file> <format> [title] Ingest a document
47
+ caas analyze <document_id> Analyze a document
48
+ caas context <document_id> [query] Extract context
49
+ caas list List all documents
50
+
51
+ Formats: pdf, html, code
52
+
53
+ Examples:
54
+ caas ingest contract.pdf pdf "Employment Contract"
55
+ caas analyze abc-123
56
+ caas context abc-123 "termination clause"
57
+ """)
58
+
59
+
60
+ def ingest_command():
61
+ """Handle ingest command."""
62
+ if len(sys.argv) < 4:
63
+ print("Usage: caas ingest <file> <format> [title]")
64
+ return
65
+
66
+ file_path = Path(sys.argv[2])
67
+ format_str = sys.argv[3]
68
+ title = sys.argv[4] if len(sys.argv) > 4 else file_path.stem
69
+
70
+ if not file_path.exists():
71
+ print(f"Error: File not found: {file_path}")
72
+ return
73
+
74
+ # Map format string to enum
75
+ format_map = {
76
+ "pdf": ContentFormat.PDF,
77
+ "html": ContentFormat.HTML,
78
+ "code": ContentFormat.CODE,
79
+ }
80
+
81
+ format_enum = format_map.get(format_str.lower())
82
+ if not format_enum:
83
+ print(f"Error: Invalid format: {format_str}")
84
+ print("Valid formats: pdf, html, code")
85
+ return
86
+
87
+ # Process document
88
+ print(f"Ingesting {file_path}...")
89
+
90
+ content = file_path.read_bytes()
91
+ processor = ProcessorFactory.get_processor(format_enum)
92
+
93
+ import uuid
94
+ doc_id = str(uuid.uuid4())
95
+
96
+ metadata = {
97
+ "id": doc_id,
98
+ "title": title,
99
+ "filename": file_path.name,
100
+ }
101
+
102
+ document = processor.process(content, metadata)
103
+
104
+ # Auto-detect and tune
105
+ detector = DocumentTypeDetector()
106
+ document.detected_type = detector.detect(document)
107
+
108
+ tuner = WeightTuner()
109
+ document = tuner.tune(document)
110
+
111
+ # Store
112
+ store = DocumentStore("caas_data.json")
113
+ store.add(document)
114
+
115
+ print(f"\n✓ Document ingested successfully!")
116
+ print(f" ID: {document.id}")
117
+ print(f" Title: {document.title}")
118
+ print(f" Detected Type: {document.detected_type}")
119
+ print(f" Sections: {len(document.sections)}")
120
+ print(f"\nTop weighted sections:")
121
+ sorted_sections = sorted(document.sections, key=lambda s: s.weight, reverse=True)
122
+ for section in sorted_sections[:5]:
123
+ print(f" - {section.title}: {section.weight}x")
124
+
125
+
126
+ def analyze_command():
127
+ """Handle analyze command."""
128
+ if len(sys.argv) < 3:
129
+ print("Usage: caas analyze <document_id>")
130
+ return
131
+
132
+ doc_id = sys.argv[2]
133
+
134
+ store = DocumentStore("caas_data.json")
135
+ document = store.get(doc_id)
136
+
137
+ if not document:
138
+ print(f"Error: Document not found: {doc_id}")
139
+ return
140
+
141
+ analyzer = StructureAnalyzer()
142
+ detector = DocumentTypeDetector()
143
+
144
+ structure = detector.detect_structure(document)
145
+ analysis = analyzer.analyze(document)
146
+
147
+ print(f"\n=== Document Analysis ===")
148
+ print(f"ID: {document.id}")
149
+ print(f"Title: {document.title}")
150
+ print(f"Type: {document.detected_type}")
151
+ print(f"\nStructure:")
152
+ print(f" Sections: {structure['section_count']}")
153
+ print(f" Clear Structure: {'Yes' if structure['has_clear_sections'] else 'No'}")
154
+ print(f" Quality: {analysis['structure_quality']}")
155
+ print(f"\nKey Sections:")
156
+ for section in structure['key_sections']:
157
+ print(f" - {section}")
158
+
159
+
160
+ def context_command():
161
+ """Handle context command."""
162
+ if len(sys.argv) < 3:
163
+ print("Usage: caas context <document_id> [query]")
164
+ return
165
+
166
+ doc_id = sys.argv[2]
167
+ query = sys.argv[3] if len(sys.argv) > 3 else ""
168
+
169
+ store = DocumentStore("caas_data.json")
170
+ document = store.get(doc_id)
171
+
172
+ if not document:
173
+ print(f"Error: Document not found: {doc_id}")
174
+ return
175
+
176
+ extractor = ContextExtractor(store)
177
+ context, metadata = extractor.extract_context(doc_id, query, max_tokens=500)
178
+
179
+ print(f"\n=== Context Extraction ===")
180
+ print(f"Document: {document.title}")
181
+ print(f"Type: {document.detected_type}")
182
+ if query:
183
+ print(f"Query: {query}")
184
+ print(f"\nSections used: {len(metadata['sections_used'])}/{metadata['total_sections']}")
185
+ for section in metadata['sections_used']:
186
+ print(f" - {section}")
187
+ print(f"\n--- Context ---")
188
+ print(context[:1000] + ("..." if len(context) > 1000 else ""))
189
+
190
+
191
+ def list_command():
192
+ """Handle list command."""
193
+ store = DocumentStore("caas_data.json")
194
+ documents = store.list_all()
195
+
196
+ if not documents:
197
+ print("No documents found.")
198
+ return
199
+
200
+ print(f"\n=== Documents ({len(documents)}) ===")
201
+ for doc in documents:
202
+ print(f"\n{doc.id}")
203
+ print(f" Title: {doc.title}")
204
+ print(f" Type: {doc.detected_type}")
205
+ print(f" Format: {doc.format}")
206
+ print(f" Sections: {len(doc.sections)}")
207
+
208
+
209
+ if __name__ == "__main__":
210
+ main()
caas/conversation.py ADDED
@@ -0,0 +1,223 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Conversation Manager for Sliding Window (FIFO) history management.
5
+
6
+ The Brutal Squeeze Philosophy:
7
+ "Chopping > Summarizing"
8
+
9
+ Instead of asking an AI to summarize conversation history (which costs money and loses nuance),
10
+ we use a brutal "Sliding Window" approach:
11
+ - Keep the last 10 turns perfectly intact
12
+ - Delete turn 11 (FIFO - First In First Out)
13
+ - No summarization = No lossy compression
14
+ - Recent Precision over Vague History
15
+
16
+ Why this works:
17
+ - Users rarely refer back to what they said 20 minutes ago
18
+ - They constantly refer to the exact code snippet they pasted 30 seconds ago
19
+ - Summary = Lossy Compression (loses specific error codes, exact wording)
20
+ - Chopping = Lossless Compression (of the recent past)
21
+
22
+ Example:
23
+ Turn 1: "I tried X and it failed with error code 500"
24
+ With Summarization: "User attempted troubleshooting" (ERROR CODE LOST!)
25
+ With Chopping: After 10 new turns, this is deleted entirely
26
+ But turns 2-11 are perfectly intact with all details
27
+ """
28
+
29
+ from typing import Dict, List, Optional, Any, Union
30
+ from datetime import datetime, timezone
31
+ import uuid
32
+ import logging
33
+
34
+ from caas.models import ConversationTurn, ConversationState
35
+
36
+ # Set up logger
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ class ConversationManager:
41
+ """
42
+ Manages conversation history using a Sliding Window (FIFO) approach.
43
+
44
+ The Sliding Window ensures:
45
+ 1. Recent precision: Last N turns are perfectly intact
46
+ 2. Zero summarization cost: No AI calls needed
47
+ 3. No information loss: What's kept is lossless
48
+ 4. Predictable behavior: Always know what's in context
49
+
50
+ Philosophy:
51
+ In a frugal architecture, we value Recent Precision over Vague History.
52
+ """
53
+
54
+ def __init__(self, max_turns: int = 10):
55
+ """
56
+ Initialize the conversation manager.
57
+
58
+ Args:
59
+ max_turns: Maximum number of turns to keep (default: 10)
60
+ """
61
+ self.state = ConversationState(max_turns=max_turns)
62
+
63
+ def add_turn(
64
+ self,
65
+ user_message: str,
66
+ ai_response: Optional[str] = None,
67
+ metadata: Optional[Dict[str, Any]] = None
68
+ ) -> str:
69
+ """
70
+ Add a conversation turn to the history.
71
+
72
+ This implements the FIFO Sliding Window:
73
+ - If we have < max_turns, just add the turn
74
+ - If we have = max_turns, delete the oldest turn and add the new one
75
+ - No summarization, no compression, just brutal chopping
76
+
77
+ Args:
78
+ user_message: The user's message
79
+ ai_response: The AI's response (optional)
80
+ metadata: Optional metadata for the turn
81
+
82
+ Returns:
83
+ The ID of the created turn
84
+ """
85
+ turn_id = str(uuid.uuid4())
86
+ turn = ConversationTurn(
87
+ id=turn_id,
88
+ user_message=user_message,
89
+ ai_response=ai_response,
90
+ timestamp=datetime.now(timezone.utc).isoformat(),
91
+ metadata=metadata or {}
92
+ )
93
+
94
+ # FIFO: If we're at max capacity, delete the oldest turn
95
+ if len(self.state.turns) >= self.state.max_turns:
96
+ deleted_turn = self.state.turns.pop(0) # Remove first (oldest) turn
97
+ logger.debug(f"FIFO: Deleted oldest turn (ID: {deleted_turn.id[:8]}...) to make room")
98
+
99
+ # Add the new turn at the end
100
+ self.state.turns.append(turn)
101
+ self.state.total_turns_ever += 1
102
+
103
+ return turn_id
104
+
105
+ def update_turn_response(self, turn_id: str, ai_response: str) -> bool:
106
+ """
107
+ Update the AI response for a specific turn.
108
+
109
+ Useful when you add a turn with just the user message
110
+ and want to update it with the AI response later.
111
+
112
+ Args:
113
+ turn_id: The ID of the turn to update
114
+ ai_response: The AI response to add
115
+
116
+ Returns:
117
+ True if turn was found and updated, False otherwise
118
+ """
119
+ for turn in self.state.turns:
120
+ if turn.id == turn_id:
121
+ turn.ai_response = ai_response
122
+ return True
123
+ return False
124
+
125
+ def get_conversation_history(
126
+ self,
127
+ include_metadata: bool = False,
128
+ format_as_text: bool = True
129
+ ) -> Union[List[ConversationTurn], str]:
130
+ """
131
+ Get the conversation history (last N turns).
132
+
133
+ Returns the history in FIFO order (oldest to newest).
134
+ All turns are perfectly intact - no summarization, no loss.
135
+
136
+ Args:
137
+ include_metadata: Whether to include metadata in text format
138
+ format_as_text: If True, return formatted text; if False, return list of turns
139
+
140
+ Returns:
141
+ Formatted conversation history or list of turns
142
+ """
143
+ if not format_as_text:
144
+ return self.state.turns
145
+
146
+ if not self.state.turns:
147
+ return "No conversation history."
148
+
149
+ # Format as text
150
+ parts = ["# Conversation History (Sliding Window)\n"]
151
+ parts.append(f"_Keeping last {self.state.max_turns} turns intact (no summarization)_\n")
152
+ parts.append(f"_Total turns ever: {self.state.total_turns_ever}_\n\n")
153
+
154
+ for i, turn in enumerate(self.state.turns, 1):
155
+ parts.append(f"## Turn {i}\n")
156
+ parts.append(f"**User**: {turn.user_message}\n")
157
+ if turn.ai_response:
158
+ parts.append(f"**AI**: {turn.ai_response}\n")
159
+ if include_metadata and turn.metadata:
160
+ parts.append(f"_Metadata: {turn.metadata}_\n")
161
+ parts.append("\n")
162
+
163
+ return "".join(parts)
164
+
165
+ def get_recent_turns(self, n: int = 5) -> List[ConversationTurn]:
166
+ """
167
+ Get the N most recent turns.
168
+
169
+ Args:
170
+ n: Number of recent turns to get
171
+
172
+ Returns:
173
+ List of recent turns (newest last)
174
+ """
175
+ return self.state.turns[-n:] if len(self.state.turns) > n else self.state.turns
176
+
177
+ def clear_conversation(self):
178
+ """Clear all conversation history."""
179
+ self.state.turns = []
180
+
181
+ def get_state(self) -> ConversationState:
182
+ """
183
+ Get the current conversation state.
184
+
185
+ Returns:
186
+ The current conversation state
187
+ """
188
+ return self.state
189
+
190
+ def set_state(self, state: ConversationState):
191
+ """
192
+ Set the conversation state.
193
+
194
+ Args:
195
+ state: The new conversation state
196
+ """
197
+ self.state = state
198
+
199
+ def get_statistics(self) -> Dict[str, Any]:
200
+ """
201
+ Get statistics about the conversation.
202
+
203
+ Returns:
204
+ Dictionary with statistics
205
+ """
206
+ if not self.state.turns:
207
+ return {
208
+ "current_turns": 0,
209
+ "max_turns": self.state.max_turns,
210
+ "total_turns_ever": self.state.total_turns_ever,
211
+ "deleted_turns": self.state.total_turns_ever,
212
+ "oldest_turn": None,
213
+ "newest_turn": None,
214
+ }
215
+
216
+ return {
217
+ "current_turns": len(self.state.turns),
218
+ "max_turns": self.state.max_turns,
219
+ "total_turns_ever": self.state.total_turns_ever,
220
+ "deleted_turns": self.state.total_turns_ever - len(self.state.turns),
221
+ "oldest_turn": self.state.turns[0].timestamp if self.state.turns else None,
222
+ "newest_turn": self.state.turns[-1].timestamp if self.state.turns else None,
223
+ }
caas/decay.py ADDED
@@ -0,0 +1,72 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ # Public Preview — basic context/memory management
4
+ """
5
+ Simple TTL-based decay for document relevance scoring.
6
+
7
+ Returns 1.0 if within TTL, 0.0 if expired, with linear interpolation between.
8
+ """
9
+
10
+ from datetime import datetime, timezone
11
+ from typing import Optional
12
+
13
+ # Default TTL in days
14
+ _DEFAULT_TTL_DAYS = 30.0
15
+
16
+
17
+ def calculate_decay_factor(
18
+ ingestion_timestamp: Optional[str],
19
+ reference_time: Optional[datetime] = None,
20
+ decay_rate: float = 1.0,
21
+ ) -> float:
22
+ """
23
+ Calculate a simple TTL-based decay factor.
24
+
25
+ Returns 1.0 when the document is brand-new and linearly decays to 0.0
26
+ at ``_DEFAULT_TTL_DAYS / decay_rate`` days old.
27
+
28
+ Args:
29
+ ingestion_timestamp: ISO-format timestamp of document ingestion.
30
+ reference_time: Time to measure from (defaults to now).
31
+ decay_rate: Higher values shorten the effective TTL.
32
+
33
+ Returns:
34
+ Decay factor between 0.0 and 1.0.
35
+ """
36
+ if not ingestion_timestamp:
37
+ return 0.0
38
+
39
+ try:
40
+ ingestion_dt = datetime.fromisoformat(
41
+ ingestion_timestamp.replace("Z", "+00:00")
42
+ )
43
+ if reference_time is None:
44
+ reference_time = datetime.now(timezone.utc)
45
+
46
+ days_elapsed = max(
47
+ 0.0, (reference_time - ingestion_dt).total_seconds() / 86400.0
48
+ )
49
+ ttl = _DEFAULT_TTL_DAYS / max(decay_rate, 0.001)
50
+ if days_elapsed >= ttl:
51
+ return 0.0
52
+ return 1.0 - (days_elapsed / ttl)
53
+ except (ValueError, AttributeError, TypeError):
54
+ return 0.0
55
+
56
+
57
+ def apply_decay_to_score(base_score: float, decay_factor: float) -> float:
58
+ """Apply *decay_factor* to *base_score*."""
59
+ return base_score * decay_factor
60
+
61
+
62
+ def get_time_weighted_score(
63
+ base_score: float,
64
+ ingestion_timestamp: Optional[str],
65
+ reference_time: Optional[datetime] = None,
66
+ decay_rate: float = 1.0,
67
+ ) -> float:
68
+ """Convenience: compute time-weighted score in one call."""
69
+ return apply_decay_to_score(
70
+ base_score,
71
+ calculate_decay_factor(ingestion_timestamp, reference_time, decay_rate),
72
+ )
@@ -0,0 +1,9 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Detection module initialization.
5
+ """
6
+
7
+ from caas.detection.detector import DocumentTypeDetector, StructureAnalyzer
8
+
9
+ __all__ = ["DocumentTypeDetector", "StructureAnalyzer"]