@macaw-ai/client 0.0.0-stage → 0.9.10

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 (142) hide show
  1. package/LICENSE.md +339 -0
  2. package/bin/install.js +278 -0
  3. package/package.json +37 -4
  4. package/payload/README.md +56 -0
  5. package/payload/secureAI/LICENSE +190 -0
  6. package/payload/secureAI/NOTICE +5 -0
  7. package/payload/secureAI/demos/policy-controls/1_uncontrolled.py +139 -0
  8. package/payload/secureAI/demos/policy-controls/2_with_macaw.py +139 -0
  9. package/payload/secureAI/demos/policy-controls/3_with_user_policies.py +162 -0
  10. package/payload/secureAI/demos/policy-controls/credentials.txt +12 -0
  11. package/payload/secureAI/demos/policy-controls/malicious_report.txt +21 -0
  12. package/payload/secureAI/demos/policy-controls/sales_report.txt +20 -0
  13. package/payload/secureAI/demos/tutorial-1-rbac/README.md +143 -0
  14. package/payload/secureAI/demos/tutorial-1-rbac/app.py +147 -0
  15. package/payload/secureAI/demos/tutorial-1-rbac/authprompts_demo.py +306 -0
  16. package/payload/secureAI/demos/tutorial-1-rbac/config/claims-config.yaml +152 -0
  17. package/payload/secureAI/demos/tutorial-1-rbac/demo_secureopenai_with_policies.py +150 -0
  18. package/payload/secureAI/demos/tutorial-1-rbac/policies/bu_Analytics.json +8 -0
  19. package/payload/secureAI/demos/tutorial-1-rbac/policies/company_FinTech_Corp.json +70 -0
  20. package/payload/secureAI/demos/tutorial-1-rbac/policies/llm-base.json +69 -0
  21. package/payload/secureAI/demos/tutorial-1-rbac/policies/team_Reporting.json +8 -0
  22. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_alice.json +32 -0
  23. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_bob.json +28 -0
  24. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_carol.json +34 -0
  25. package/payload/secureAI/demos/tutorial-1-rbac/requirements.txt +6 -0
  26. package/payload/secureAI/demos/tutorial-1-rbac/setup/auth0_complete_setup.sh +392 -0
  27. package/payload/secureAI/demos/tutorial-1-rbac/setup/keycloak_complete_setup.sh +320 -0
  28. package/payload/secureAI/demos/tutorial-2-intent/Policies/alation-remote-proxy.json +155 -0
  29. package/payload/secureAI/demos/tutorial-2-intent/Policies/bu.json +22 -0
  30. package/payload/secureAI/demos/tutorial-2-intent/Policies/company.json +17 -0
  31. package/payload/secureAI/demos/tutorial-2-intent/Policies/user_alice.json +48 -0
  32. package/payload/secureAI/demos/tutorial-2-intent/Policies/user_bob.json +83 -0
  33. package/payload/secureAI/demos/tutorial-2-intent/README.md +213 -0
  34. package/payload/secureAI/demos/tutorial-2-intent/script.py +188 -0
  35. package/payload/secureAI/demos/tutorial-2-intent/setup/alation_verifier.py +177 -0
  36. package/payload/secureAI/demos/tutorial-2-intent/setup/get_alation_user_token.py +180 -0
  37. package/payload/secureAI/examples/README.md +244 -0
  38. package/payload/secureAI/examples/anthropic/anthropic_1a_dropin_simple.py +103 -0
  39. package/payload/secureAI/examples/anthropic/anthropic_1b_multiuser_bind.py +190 -0
  40. package/payload/secureAI/examples/anthropic/anthropic_1b_multiuser_bind_streaming.py +190 -0
  41. package/payload/secureAI/examples/anthropic/anthropic_1c_a2a_invoke.py +156 -0
  42. package/payload/secureAI/examples/attestations/1a_trade_alice.py +215 -0
  43. package/payload/secureAI/examples/attestations/1a_trade_bob.py +164 -0
  44. package/payload/secureAI/examples/attestations/1b_grant_admin.py +170 -0
  45. package/payload/secureAI/examples/attestations/1b_grant_researcher.py +231 -0
  46. package/payload/secureAI/examples/attestations/README.md +128 -0
  47. package/payload/secureAI/examples/langchain/langchain_1a_dropin_simple.py +199 -0
  48. package/payload/secureAI/examples/langchain/langchain_1b_multiuser.py +262 -0
  49. package/payload/secureAI/examples/langchain/langchain_1c_orchestration.py +332 -0
  50. package/payload/secureAI/examples/langchain/langchain_1d_llm_openai.py +130 -0
  51. package/payload/secureAI/examples/langchain/langchain_1e_llm_anthropic.py +130 -0
  52. package/payload/secureAI/examples/langchain/langchain_1f_memory.py +214 -0
  53. package/payload/secureAI/examples/litellm/litellm_1a_dropin_simple.py +131 -0
  54. package/payload/secureAI/examples/mcp/1a_simple_invocation.py +115 -0
  55. package/payload/secureAI/examples/mcp/1b_discovery_and_resources.py +142 -0
  56. package/payload/secureAI/examples/mcp/1c_logging_client.py +100 -0
  57. package/payload/secureAI/examples/mcp/1d_progress_client.py +100 -0
  58. package/payload/secureAI/examples/mcp/1e_sampling_client.py +150 -0
  59. package/payload/secureAI/examples/mcp/1e_sampling_server.py +90 -0
  60. package/payload/secureAI/examples/mcp/1f_elicitation_client.py +127 -0
  61. package/payload/secureAI/examples/mcp/1f_elicitation_server.py +73 -0
  62. package/payload/secureAI/examples/mcp/1g_roots_client.py +122 -0
  63. package/payload/secureAI/examples/mcp/1g_roots_server.py +85 -0
  64. package/payload/secureAI/examples/mcp/2a_proxy_snowflake.py +212 -0
  65. package/payload/secureAI/examples/mcp/2b_proxy_databricks.py +299 -0
  66. package/payload/secureAI/examples/mcp/2c_proxy_stdio_fetch.py +91 -0
  67. package/payload/secureAI/examples/mcp/2d_proxy_stdio_salesforce.py +119 -0
  68. package/payload/secureAI/examples/mcp/2e_proxy_multiuser.py +136 -0
  69. package/payload/secureAI/examples/mcp/2f_proxy_stdio_databricks.py +144 -0
  70. package/payload/secureAI/examples/mcp/3a_native_mcp_client.py +104 -0
  71. package/payload/secureAI/examples/mcp/3b_native_mcp_proxy.py +114 -0
  72. package/payload/secureAI/examples/mcp/3c_native_mcp_sampling.py +180 -0
  73. package/payload/secureAI/examples/mcp/3d_native_mcp_2026.py +135 -0
  74. package/payload/secureAI/examples/mcp/securemcp_calculator.py +248 -0
  75. package/payload/secureAI/examples/mcp/securemcp_server.py +75 -0
  76. package/payload/secureAI/examples/openai/openai_1a_dropin_simple.py +102 -0
  77. package/payload/secureAI/examples/openai/openai_1b_multiuser_bind.py +193 -0
  78. package/payload/secureAI/examples/openai/openai_1b_multiuser_bind_streaming.py +199 -0
  79. package/payload/secureAI/examples/openai/openai_1c_a2a_invoke.py +156 -0
  80. package/payload/secureAI/examples/openai/openai_1d_invocation_patterns.py +337 -0
  81. package/payload/secureAI/examples/phishing-resistance/1a_login_alice.py +180 -0
  82. package/payload/secureAI/examples/phishing-resistance/1b_trade_alice.py +241 -0
  83. package/payload/secureAI/examples/phishing-resistance/1b_trade_bob.py +164 -0
  84. package/payload/secureAI/examples/phishing-resistance/README.md +124 -0
  85. package/payload/secureAI/examples/phishing-resistance/get_token.py +114 -0
  86. package/payload/secureAI/examples/pydantic_ai/README.md +88 -0
  87. package/payload/secureAI/examples/pydantic_ai/policies/app_pydantic-agent.json +10 -0
  88. package/payload/secureAI/examples/pydantic_ai/pydanticai_1a_dropin_simple.py +90 -0
  89. package/payload/secureAI/examples/pydantic_ai/pydanticai_1b_model_routing.py +85 -0
  90. package/payload/secureAI/examples/pydantic_ai/pydanticai_1c_native_tools.py +83 -0
  91. package/payload/secureAI/examples/pydantic_ai/pydanticai_1d_multiuser_bind.py +104 -0
  92. package/payload/secureAI/examples/pydantic_ai/pydanticai_1e_mcp_compose.py +92 -0
  93. package/payload/secureAI/macaw_adapters/__init__.py +55 -0
  94. package/payload/secureAI/macaw_adapters/anthropic/REFERENCE.md +374 -0
  95. package/payload/secureAI/macaw_adapters/anthropic/__init__.py +22 -0
  96. package/payload/secureAI/macaw_adapters/anthropic/secure_anthropic.py +792 -0
  97. package/payload/secureAI/macaw_adapters/anthropic_ext_tools/__init__.py +25 -0
  98. package/payload/secureAI/macaw_adapters/anthropic_ext_tools/secure_anthropic.py +840 -0
  99. package/payload/secureAI/macaw_adapters/langchain/REFERENCE.md +234 -0
  100. package/payload/secureAI/macaw_adapters/langchain/__init__.py +100 -0
  101. package/payload/secureAI/macaw_adapters/langchain/_utils.py +83 -0
  102. package/payload/secureAI/macaw_adapters/langchain/agents.py +296 -0
  103. package/payload/secureAI/macaw_adapters/langchain/anthropic.py +456 -0
  104. package/payload/secureAI/macaw_adapters/langchain/callbacks.py +306 -0
  105. package/payload/secureAI/macaw_adapters/langchain/memory.py +352 -0
  106. package/payload/secureAI/macaw_adapters/langchain/openai.py +410 -0
  107. package/payload/secureAI/macaw_adapters/langchain/tools.py +174 -0
  108. package/payload/secureAI/macaw_adapters/litellm/README.md +216 -0
  109. package/payload/secureAI/macaw_adapters/litellm/__init__.py +143 -0
  110. package/payload/secureAI/macaw_adapters/litellm/secure_litellm.py +686 -0
  111. package/payload/secureAI/macaw_adapters/mcp/REFERENCE.md +460 -0
  112. package/payload/secureAI/macaw_adapters/mcp/__init__.py +65 -0
  113. package/payload/secureAI/macaw_adapters/mcp/_endpoint.py +193 -0
  114. package/payload/secureAI/macaw_adapters/mcp/_endpoint2.py +225 -0
  115. package/payload/secureAI/macaw_adapters/mcp/_serve.py +25 -0
  116. package/payload/secureAI/macaw_adapters/mcp/client.py +721 -0
  117. package/payload/secureAI/macaw_adapters/mcp/decorators.py +228 -0
  118. package/payload/secureAI/macaw_adapters/mcp/fastmcp_compat.py +353 -0
  119. package/payload/secureAI/macaw_adapters/mcp/mcp.py +785 -0
  120. package/payload/secureAI/macaw_adapters/mcp/proxy.py +626 -0
  121. package/payload/secureAI/macaw_adapters/mcp/server.py +317 -0
  122. package/payload/secureAI/macaw_adapters/mcp/subscriptions.py +450 -0
  123. package/payload/secureAI/macaw_adapters/openai/REFERENCE.md +368 -0
  124. package/payload/secureAI/macaw_adapters/openai/__init__.py +22 -0
  125. package/payload/secureAI/macaw_adapters/openai/secure_openai.py +833 -0
  126. package/payload/secureAI/macaw_adapters/openai_ext_tools/REFERENCE.md +368 -0
  127. package/payload/secureAI/macaw_adapters/openai_ext_tools/__init__.py +25 -0
  128. package/payload/secureAI/macaw_adapters/openai_ext_tools/secure_openai.py +876 -0
  129. package/payload/secureAI/macaw_adapters/pydantic_ai/__init__.py +36 -0
  130. package/payload/secureAI/macaw_adapters/pydantic_ai/_core.py +257 -0
  131. package/payload/secureAI/macaw_adapters/pydantic_ai/agent.py +218 -0
  132. package/payload/secureAI/macaw_adapters/pydantic_ai/model.py +99 -0
  133. package/payload/secureAI/macaw_adapters/pydantic_ai/toolset.py +86 -0
  134. package/payload/secureAI/test_harness_quick.py +296 -0
  135. package/wheels/macaw_adapters-0.9.10.1-py3-none-any.whl +0 -0
  136. package/wheels/macaw_client-0.9.10.1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  137. package/wheels/macaw_client-0.9.10.1-cp312-cp312-manylinux_2_17_x86_64.whl +0 -0
  138. package/wheels/macaw_client-0.9.10.1-cp314-cp314-macosx_11_0_arm64.whl +0 -0
  139. package/wheels/macaw_client-0.9.10.1-cp314-cp314-manylinux_2_17_x86_64.whl +0 -0
  140. package/wheels/macaw_client-0.9.10.1-cp314-cp314-win_amd64.whl +0 -0
  141. package/wheels/macaw_client-0.9.10.1-cp39-cp39-macosx_11_0_arm64.whl +0 -0
  142. package/README.md +0 -3
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ langchain_1d_llm_openai.py - SecureChatOpenAI drop-in replacement
4
+
5
+ Drop-in replacement for langchain_openai.ChatOpenAI with MACAW protection.
6
+ Demonstrates invoke and streaming with audit logging.
7
+
8
+ Use this when: You want MACAW security on LangChain OpenAI calls without
9
+ changing your application code.
10
+
11
+ Prerequisites:
12
+ - MACAW SDK installed (pip install macaw-client macaw-adapters)
13
+ - OPENAI_API_KEY environment variable
14
+
15
+ Run:
16
+ export OPENAI_API_KEY=sk-...
17
+ python langchain_1d_llm_openai.py
18
+ """
19
+
20
+ import os
21
+
22
+ # BEFORE: from langchain_openai import ChatOpenAI
23
+ # AFTER:
24
+ from macaw_adapters.langchain.openai import ChatOpenAI, cleanup
25
+
26
+
27
+ def main():
28
+ # Check for API key
29
+ if not os.environ.get("OPENAI_API_KEY"):
30
+ print("Set OPENAI_API_KEY environment variable")
31
+ print(" export OPENAI_API_KEY=sk-...")
32
+ return
33
+
34
+ print("=" * 60)
35
+ print("Example 1d: SecureChatOpenAI (LangChain)")
36
+ print("=" * 60)
37
+ print("\nPattern: Drop-in replacement for langchain_openai.ChatOpenAI")
38
+ print("Use when: Add MACAW audit logging to LangChain OpenAI calls")
39
+ print("\nImport change:")
40
+ print(" BEFORE: from langchain_openai import ChatOpenAI")
41
+ print(" AFTER: from macaw_adapters.langchain.openai import ChatOpenAI")
42
+
43
+ # Create SecureChatOpenAI - same API as langchain_openai.ChatOpenAI
44
+ print("\n--- Creating SecureChatOpenAI ---")
45
+ llm = ChatOpenAI(
46
+ model="gpt-3.5-turbo",
47
+ temperature=0.7,
48
+ max_tokens=100
49
+ )
50
+ print(f"Model: {llm.model_name}")
51
+ print(f"Temperature: {llm.temperature}")
52
+
53
+ # Test 1: Basic invoke
54
+ print("\n--- Test 1: Basic invoke ---")
55
+ try:
56
+ response = llm.invoke("What is 2 + 2? Answer in one word.")
57
+ print(f"Response: {response.content}")
58
+ print("(This call was audit-logged by MACAW)")
59
+ except Exception as e:
60
+ print(f"Error: {e}")
61
+
62
+ # Test 2: Invoke with message list
63
+ print("\n--- Test 2: Invoke with messages ---")
64
+ try:
65
+ from langchain_core.messages import HumanMessage, SystemMessage
66
+ messages = [
67
+ SystemMessage(content="You are a helpful assistant. Be concise."),
68
+ HumanMessage(content="Name three primary colors.")
69
+ ]
70
+ response = llm.invoke(messages)
71
+ print(f"Response: {response.content}")
72
+ except ImportError:
73
+ print("Skipping (langchain_core not installed)")
74
+ except Exception as e:
75
+ print(f"Error: {e}")
76
+
77
+ # Test 3: Streaming
78
+ print("\n--- Test 3: Streaming ---")
79
+ try:
80
+ print("Response: ", end="", flush=True)
81
+ for chunk in llm.stream("Count from 1 to 5, one number per line."):
82
+ if hasattr(chunk, 'content'):
83
+ print(chunk.content, end="", flush=True)
84
+ else:
85
+ print(chunk, end="", flush=True)
86
+ print("\n(Streaming call was audit-logged by MACAW)")
87
+ except Exception as e:
88
+ print(f"\nError: {e}")
89
+
90
+ # Test 4: Batch
91
+ print("\n--- Test 4: Batch ---")
92
+ try:
93
+ prompts = [
94
+ "What color is the sky? One word.",
95
+ "What color is grass? One word."
96
+ ]
97
+ responses = llm.batch(prompts)
98
+ for i, resp in enumerate(responses):
99
+ print(f" Q{i+1}: {prompts[i]}")
100
+ print(f" A{i+1}: {resp.content}")
101
+ except Exception as e:
102
+ print(f"Error: {e}")
103
+
104
+ # Cleanup
105
+ print("\n--- Cleanup ---")
106
+ cleanup()
107
+
108
+ print("\n" + "=" * 60)
109
+ print("Example complete!")
110
+ print("=" * 60)
111
+ print("\nKey points:")
112
+ print(" - Same API as langchain_openai.ChatOpenAI")
113
+ print(" - All calls audit-logged through MACAW")
114
+ print(" - Supports invoke, stream, batch, and async variants")
115
+
116
+
117
+ if __name__ == "__main__":
118
+ try:
119
+ main()
120
+ except Exception as e:
121
+ err = str(e)
122
+ print("\n" + "=" * 60)
123
+ if "OPENAI_API_KEY" in err or "api_key" in err.lower():
124
+ print("ERROR: OpenAI API key not configured")
125
+ print("Fix: export OPENAI_API_KEY=sk-...")
126
+ else:
127
+ print(f"ERROR: {e}")
128
+ print("=" * 60)
129
+ import sys
130
+ sys.exit(1)
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ langchain_1e_llm_anthropic.py - SecureChatAnthropic drop-in replacement
4
+
5
+ Drop-in replacement for langchain_anthropic.ChatAnthropic with MACAW protection.
6
+ Demonstrates invoke and streaming with audit logging.
7
+
8
+ Use this when: You want MACAW security on LangChain Anthropic calls without
9
+ changing your application code.
10
+
11
+ Prerequisites:
12
+ - MACAW SDK installed (pip install macaw-client macaw-adapters)
13
+ - ANTHROPIC_API_KEY environment variable
14
+
15
+ Run:
16
+ export ANTHROPIC_API_KEY=sk-ant-...
17
+ python langchain_1e_llm_anthropic.py
18
+ """
19
+
20
+ import os
21
+
22
+ # BEFORE: from langchain_anthropic import ChatAnthropic
23
+ # AFTER:
24
+ from macaw_adapters.langchain.anthropic import ChatAnthropic, cleanup
25
+
26
+
27
+ def main():
28
+ # Check for API key
29
+ if not os.environ.get("ANTHROPIC_API_KEY"):
30
+ print("Set ANTHROPIC_API_KEY environment variable")
31
+ print(" export ANTHROPIC_API_KEY=sk-ant-...")
32
+ return
33
+
34
+ print("=" * 60)
35
+ print("Example 1e: SecureChatAnthropic (LangChain)")
36
+ print("=" * 60)
37
+ print("\nPattern: Drop-in replacement for langchain_anthropic.ChatAnthropic")
38
+ print("Use when: Add MACAW audit logging to LangChain Anthropic calls")
39
+ print("\nImport change:")
40
+ print(" BEFORE: from langchain_anthropic import ChatAnthropic")
41
+ print(" AFTER: from macaw_adapters.langchain.anthropic import ChatAnthropic")
42
+
43
+ # Create SecureChatAnthropic - same API as langchain_anthropic.ChatAnthropic
44
+ print("\n--- Creating SecureChatAnthropic ---")
45
+ llm = ChatAnthropic(
46
+ model="claude-3-haiku-20240307", # Fast model for demo
47
+ temperature=0.7,
48
+ max_tokens=100
49
+ )
50
+ print(f"Model: {llm.model_name}")
51
+ print(f"Temperature: {llm.temperature}")
52
+
53
+ # Test 1: Basic invoke
54
+ print("\n--- Test 1: Basic invoke ---")
55
+ try:
56
+ response = llm.invoke("What is 2 + 2? Answer in one word.")
57
+ print(f"Response: {response.content}")
58
+ print("(This call was audit-logged by MACAW)")
59
+ except Exception as e:
60
+ print(f"Error: {e}")
61
+
62
+ # Test 2: Invoke with message list
63
+ print("\n--- Test 2: Invoke with messages ---")
64
+ try:
65
+ from langchain_core.messages import HumanMessage, SystemMessage
66
+ messages = [
67
+ SystemMessage(content="You are a helpful assistant. Be concise."),
68
+ HumanMessage(content="Name three primary colors.")
69
+ ]
70
+ response = llm.invoke(messages)
71
+ print(f"Response: {response.content}")
72
+ except ImportError:
73
+ print("Skipping (langchain_core not installed)")
74
+ except Exception as e:
75
+ print(f"Error: {e}")
76
+
77
+ # Test 3: Streaming
78
+ print("\n--- Test 3: Streaming ---")
79
+ try:
80
+ print("Response: ", end="", flush=True)
81
+ for chunk in llm.stream("Count from 1 to 5, one number per line."):
82
+ if hasattr(chunk, 'content'):
83
+ print(chunk.content, end="", flush=True)
84
+ else:
85
+ print(chunk, end="", flush=True)
86
+ print("\n(Streaming call was audit-logged by MACAW)")
87
+ except Exception as e:
88
+ print(f"\nError: {e}")
89
+
90
+ # Test 4: Batch
91
+ print("\n--- Test 4: Batch ---")
92
+ try:
93
+ prompts = [
94
+ "What color is the sky? One word.",
95
+ "What color is grass? One word."
96
+ ]
97
+ responses = llm.batch(prompts)
98
+ for i, resp in enumerate(responses):
99
+ print(f" Q{i+1}: {prompts[i]}")
100
+ print(f" A{i+1}: {resp.content}")
101
+ except Exception as e:
102
+ print(f"Error: {e}")
103
+
104
+ # Cleanup
105
+ print("\n--- Cleanup ---")
106
+ cleanup()
107
+
108
+ print("\n" + "=" * 60)
109
+ print("Example complete!")
110
+ print("=" * 60)
111
+ print("\nKey points:")
112
+ print(" - Same API as langchain_anthropic.ChatAnthropic")
113
+ print(" - All calls audit-logged through MACAW")
114
+ print(" - Supports invoke, stream, batch, and async variants")
115
+
116
+
117
+ if __name__ == "__main__":
118
+ try:
119
+ main()
120
+ except Exception as e:
121
+ err = str(e)
122
+ print("\n" + "=" * 60)
123
+ if "ANTHROPIC_API_KEY" in err or "api_key" in err.lower():
124
+ print("ERROR: Anthropic API key not configured")
125
+ print("Fix: export ANTHROPIC_API_KEY=sk-ant-...")
126
+ else:
127
+ print(f"ERROR: {e}")
128
+ print("=" * 60)
129
+ import sys
130
+ sys.exit(1)
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ langchain_1f_memory.py - Secure Memory with MACAW context backing
4
+
5
+ Drop-in replacement for LangChain memory classes with MACAW context backing.
6
+ Demonstrates multi-session isolation where each user gets separate memory.
7
+
8
+ Use this when: You want conversation memory backed by MACAW's secure context
9
+ vault with audit logging and session isolation.
10
+
11
+ Prerequisites:
12
+ - MACAW SDK installed (pip install macaw-client macaw-adapters)
13
+ - OPENAI_API_KEY environment variable (optional, for LLM demo)
14
+
15
+ Run:
16
+ python langchain_1f_memory.py
17
+ # Or with OpenAI demo:
18
+ export OPENAI_API_KEY=sk-...
19
+ python langchain_1f_memory.py
20
+ """
21
+
22
+ import os
23
+
24
+ # BEFORE: from langchain.memory import ConversationBufferMemory
25
+ # AFTER:
26
+ from macaw_adapters.langchain.memory import (
27
+ ConversationBufferMemory,
28
+ ConversationBufferWindowMemory,
29
+ cleanup
30
+ )
31
+ from macaw_adapters.langchain.openai import ChatOpenAI
32
+
33
+
34
+ def demonstrate_basic_memory():
35
+ """Basic memory usage."""
36
+ print("\n--- Basic ConversationBufferMemory ---")
37
+
38
+ memory = ConversationBufferMemory(session_id="demo-session")
39
+
40
+ # Simulate conversation
41
+ memory.save_context(
42
+ {"input": "Hi, my name is Alice"},
43
+ {"output": "Hello Alice! How can I help you today?"}
44
+ )
45
+ memory.save_context(
46
+ {"input": "What's the weather like?"},
47
+ {"output": "I don't have real-time weather data, but I can help you find it."}
48
+ )
49
+
50
+ # Load memory
51
+ history = memory.load_memory_variables({})
52
+ print(f"Conversation history:\n{history['history']}")
53
+ print("\n(All memory operations audit-logged by MACAW)")
54
+
55
+ return memory
56
+
57
+
58
+ def demonstrate_multi_session():
59
+ """Multi-session isolation - each user gets separate memory."""
60
+ print("\n--- Multi-Session Isolation ---")
61
+ print("Each user has isolated memory (different session_id)")
62
+
63
+ # Alice's session
64
+ alice_memory = ConversationBufferMemory(session_id="alice-session")
65
+ alice_memory.save_context(
66
+ {"input": "I want to order pizza"},
67
+ {"output": "What toppings would you like?"}
68
+ )
69
+ alice_memory.save_context(
70
+ {"input": "Pepperoni please"},
71
+ {"output": "One pepperoni pizza coming up!"}
72
+ )
73
+
74
+ # Bob's session (completely isolated)
75
+ bob_memory = ConversationBufferMemory(session_id="bob-session")
76
+ bob_memory.save_context(
77
+ {"input": "I need help with my order"},
78
+ {"output": "Of course! What's your order number?"}
79
+ )
80
+ bob_memory.save_context(
81
+ {"input": "Order #12345"},
82
+ {"output": "I found your order. How can I help?"}
83
+ )
84
+
85
+ # Show isolation
86
+ print("\nAlice's memory:")
87
+ alice_hist = alice_memory.load_memory_variables({})
88
+ print(f" {alice_hist['history']}")
89
+
90
+ print("\nBob's memory:")
91
+ bob_hist = bob_memory.load_memory_variables({})
92
+ print(f" {bob_hist['history']}")
93
+
94
+ print("\n(Sessions are isolated - Bob can't see Alice's conversation)")
95
+
96
+ return alice_memory, bob_memory
97
+
98
+
99
+ def demonstrate_window_memory():
100
+ """Window memory - only keeps last k turns."""
101
+ print("\n--- ConversationBufferWindowMemory (k=2) ---")
102
+ print("Only keeps last 2 conversation turns")
103
+
104
+ memory = ConversationBufferWindowMemory(k=2, session_id="window-demo")
105
+
106
+ # Add 4 turns
107
+ conversations = [
108
+ ("Turn 1: Hello", "Hi there!"),
109
+ ("Turn 2: How are you?", "I'm doing well!"),
110
+ ("Turn 3: What's your name?", "I'm an AI assistant."),
111
+ ("Turn 4: Can you help me?", "Of course! What do you need?"),
112
+ ]
113
+
114
+ for user_msg, ai_msg in conversations:
115
+ memory.save_context({"input": user_msg}, {"output": ai_msg})
116
+
117
+ # Only last 2 turns should be visible
118
+ history = memory.load_memory_variables({})
119
+ print(f"Window memory (last 2 turns only):\n{history['history']}")
120
+
121
+ return memory
122
+
123
+
124
+ def demonstrate_with_llm():
125
+ """Use memory with actual LLM (if API key available)."""
126
+ if not os.environ.get("OPENAI_API_KEY"):
127
+ print("\n--- Skipping LLM demo (no OPENAI_API_KEY) ---")
128
+ return
129
+
130
+ print("\n--- Memory with SecureChatOpenAI ---")
131
+
132
+ llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7, max_tokens=50)
133
+ memory = ConversationBufferMemory(session_id="llm-demo")
134
+
135
+ # First turn
136
+ user_input = "My favorite color is blue."
137
+ print(f"User: {user_input}")
138
+
139
+ response = llm.invoke(f"The user said: {user_input}. Acknowledge this.")
140
+ ai_output = response.content
141
+ print(f"AI: {ai_output}")
142
+
143
+ memory.save_context({"input": user_input}, {"output": ai_output})
144
+
145
+ # Second turn - AI should remember
146
+ user_input2 = "What did I just tell you?"
147
+ print(f"\nUser: {user_input2}")
148
+
149
+ history = memory.load_memory_variables({})
150
+ context = f"Previous conversation:\n{history['history']}\n\nUser: {user_input2}"
151
+
152
+ response2 = llm.invoke(context)
153
+ print(f"AI: {response2.content}")
154
+
155
+ memory.save_context({"input": user_input2}, {"output": response2.content})
156
+
157
+ print("\n(Memory backed by MACAW context vault)")
158
+
159
+
160
+ def main():
161
+ print("=" * 60)
162
+ print("Example 1f: Secure Memory (LangChain)")
163
+ print("=" * 60)
164
+ print("\nPattern: Drop-in replacement for langchain.memory classes")
165
+ print("Use when: Need conversation memory with MACAW context backing")
166
+ print("\nImport change:")
167
+ print(" BEFORE: from langchain.memory import ConversationBufferMemory")
168
+ print(" AFTER: from macaw_adapters.langchain.memory import ConversationBufferMemory")
169
+
170
+ # Demo 1: Basic memory
171
+ basic_memory = demonstrate_basic_memory()
172
+
173
+ # Demo 2: Multi-session isolation
174
+ alice_memory, bob_memory = demonstrate_multi_session()
175
+
176
+ # Demo 3: Window memory
177
+ window_memory = demonstrate_window_memory()
178
+
179
+ # Demo 4: With actual LLM
180
+ demonstrate_with_llm()
181
+
182
+ # Cleanup
183
+ print("\n--- Cleanup ---")
184
+ basic_memory.clear()
185
+ alice_memory.clear()
186
+ bob_memory.clear()
187
+ window_memory.clear()
188
+ cleanup()
189
+
190
+ print("\n" + "=" * 60)
191
+ print("Example complete!")
192
+ print("=" * 60)
193
+ print("\nKey points:")
194
+ print(" - Same API as langchain.memory classes")
195
+ print(" - Memory backed by MACAW context vault")
196
+ print(" - All operations audit-logged")
197
+ print(" - Session isolation via session_id")
198
+ print(" - Supports: ConversationBufferMemory, WindowMemory, SummaryMemory")
199
+
200
+
201
+ if __name__ == "__main__":
202
+ try:
203
+ main()
204
+ except Exception as e:
205
+ err = str(e)
206
+ print("\n" + "=" * 60)
207
+ if "OPENAI_API_KEY" in err or "api_key" in err.lower():
208
+ print("ERROR: OpenAI API key not configured")
209
+ print("Fix: export OPENAI_API_KEY=sk-...")
210
+ else:
211
+ print(f"ERROR: {e}")
212
+ print("=" * 60)
213
+ import sys
214
+ sys.exit(1)
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ litellm_1a_dropin_simple.py - Drop-in replacement for LiteLLM
4
+
5
+ The simplest integration path - just replace your import and it works.
6
+ No Identity Provider needed. Tests multiple providers through unified API.
7
+
8
+ Prerequisites:
9
+ - MACAW SDK installed (pip install macaw-client macaw-adapters[litellm])
10
+ - OPENAI_API_KEY and/or ANTHROPIC_API_KEY environment variables
11
+
12
+ Run:
13
+ export OPENAI_API_KEY=sk-...
14
+ export ANTHROPIC_API_KEY=sk-ant-...
15
+ python litellm_1a_dropin_simple.py
16
+ """
17
+
18
+ import os
19
+ import sys
20
+
21
+ # BEFORE: import litellm
22
+ # AFTER:
23
+ from macaw_adapters.litellm import SecureLiteLLM
24
+
25
+
26
+ def main():
27
+ # Check for at least one API key
28
+ has_openai = bool(os.environ.get("OPENAI_API_KEY"))
29
+ has_anthropic = bool(os.environ.get("ANTHROPIC_API_KEY"))
30
+
31
+ if not has_openai and not has_anthropic:
32
+ print("Set at least one API key:")
33
+ print(" export OPENAI_API_KEY=sk-...")
34
+ print(" export ANTHROPIC_API_KEY=sk-ant-...")
35
+ return
36
+
37
+ print("=" * 60)
38
+ print("Example 1a: Drop-in Replacement (LiteLLM)")
39
+ print("=" * 60)
40
+ print("\nPath: Direct on service (simplest)")
41
+ print("Use when: Single app, multiple providers, app-level policies")
42
+ print(f"\nProviders available: OpenAI={has_openai}, Anthropic={has_anthropic}")
43
+
44
+ # Define allowed models - only cheaper/faster models
45
+ allowed_models = []
46
+ if has_openai:
47
+ allowed_models.append("openai/gpt-3.5-turbo")
48
+ if has_anthropic:
49
+ allowed_models.append("anthropic/claude-3-haiku-20240307")
50
+
51
+ # Create SecureLiteLLM with policy restricting to allowed models
52
+ client = SecureLiteLLM(
53
+ app_name="my-litellm-app",
54
+ intent_policy={
55
+ "constraints": {
56
+ "parameters": {
57
+ "tool:*/generate": {
58
+ "model": allowed_models,
59
+ "max_tokens": {"max": 200}
60
+ }
61
+ }
62
+ }
63
+ }
64
+ )
65
+
66
+ print(f"\nService registered: {client.server_id}")
67
+ print(f"Mode: {client._mode}")
68
+ print(f"Policy: Only {allowed_models}, max 200 tokens")
69
+
70
+ # Test 1: OpenAI backend (if available)
71
+ if has_openai:
72
+ print("\n--- Test 1: OpenAI backend (gpt-3.5-turbo) ---")
73
+ response = client.chat.completions.create(
74
+ model="openai/gpt-3.5-turbo",
75
+ max_tokens=100,
76
+ messages=[
77
+ {"role": "user", "content": "What is 2+2? One word answer."}
78
+ ]
79
+ )
80
+ print(f"Model: {response.model}")
81
+ print(f"Response: {response.choices[0].message.content}")
82
+
83
+ # Test 2: Anthropic backend (if available)
84
+ if has_anthropic:
85
+ print("\n--- Test 2: Anthropic backend (claude-3-haiku) ---")
86
+ response = client.chat.completions.create(
87
+ model="anthropic/claude-3-haiku-20240307",
88
+ max_tokens=100,
89
+ messages=[
90
+ {"role": "user", "content": "What is 3+3? One word answer."}
91
+ ]
92
+ )
93
+ print(f"Model: {response.model}")
94
+ print(f"Response: {response.choices[0].message.content}")
95
+
96
+ # Test 3: Policy enforcement - try a blocked model
97
+ print("\n--- Test 3: Policy enforcement (blocked model) ---")
98
+ blocked_model = "openai/gpt-4" if has_openai else "anthropic/claude-3-5-sonnet-20241022"
99
+ print(f"Trying blocked model: {blocked_model}")
100
+
101
+ try:
102
+ response = client.chat.completions.create(
103
+ model=blocked_model,
104
+ max_tokens=100,
105
+ messages=[
106
+ {"role": "user", "content": "Hello"}
107
+ ]
108
+ )
109
+ print(f"Unexpected success - should have been blocked!")
110
+ print(f"Response: {response.choices[0].message.content[:50]}...")
111
+ except Exception as e:
112
+ print(f"Correctly blocked: {e}")
113
+
114
+ print("\n" + "=" * 60)
115
+ print("Example complete!")
116
+ print("=" * 60)
117
+
118
+
119
+ if __name__ == "__main__":
120
+ try:
121
+ main()
122
+ except Exception as e:
123
+ err = str(e)
124
+ print("\n" + "=" * 60)
125
+ if "api_key" in err.lower():
126
+ print("ERROR: API key not configured")
127
+ print("Fix: export OPENAI_API_KEY=sk-... or ANTHROPIC_API_KEY=sk-ant-...")
128
+ else:
129
+ print(f"ERROR: {e}")
130
+ print("=" * 60)
131
+ sys.exit(1)