reminix-llamaindex 0.0.1__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.
@@ -0,0 +1,3 @@
1
+ from .adapter import LlamaIndexAdapter, wrap
2
+
3
+ __all__ = ["LlamaIndexAdapter", "wrap"]
@@ -0,0 +1,179 @@
1
+ """LlamaIndex adapter for Reminix Runtime."""
2
+
3
+ import json
4
+ from collections.abc import AsyncIterator
5
+ from typing import Any, Protocol, runtime_checkable
6
+
7
+ from reminix_runtime import (
8
+ BaseAdapter,
9
+ ChatRequest,
10
+ ChatResponse,
11
+ InvokeRequest,
12
+ InvokeResponse,
13
+ Message,
14
+ )
15
+
16
+
17
+ @runtime_checkable
18
+ class ChatEngine(Protocol):
19
+ """Protocol for LlamaIndex chat engines."""
20
+
21
+ async def achat(self, message: str) -> Any:
22
+ """Async chat method."""
23
+ ...
24
+
25
+ async def astream_chat(self, message: str) -> Any:
26
+ """Async streaming chat method."""
27
+ ...
28
+
29
+
30
+ class LlamaIndexAdapter(BaseAdapter):
31
+ """Adapter for LlamaIndex chat engines."""
32
+
33
+ adapter_name = "llamaindex"
34
+
35
+ def __init__(self, engine: ChatEngine, name: str = "llamaindex-agent") -> None:
36
+ """Initialize the adapter.
37
+
38
+ Args:
39
+ engine: A LlamaIndex chat engine (e.g., SimpleChatEngine, ContextChatEngine).
40
+ name: Name for the agent.
41
+ """
42
+ self._engine = engine
43
+ self._name = name
44
+
45
+ @property
46
+ def name(self) -> str:
47
+ return self._name
48
+
49
+ def _get_last_user_message(self, messages: list[Message]) -> str:
50
+ """Get the last user message from the conversation."""
51
+ for message in reversed(messages):
52
+ if message.role == "user":
53
+ return message.content or ""
54
+ # Fallback to last message if no user message found
55
+ return messages[-1].content or "" if messages else ""
56
+
57
+ async def invoke(self, request: InvokeRequest) -> InvokeResponse:
58
+ """Handle an invoke request.
59
+
60
+ For task-oriented operations. Expects input with 'query' or 'prompt' key.
61
+
62
+ Args:
63
+ request: The invoke request with input data.
64
+
65
+ Returns:
66
+ The invoke response with the output.
67
+ """
68
+ # Extract query from input
69
+ if "query" in request.input:
70
+ query = request.input["query"]
71
+ elif "prompt" in request.input:
72
+ query = request.input["prompt"]
73
+ elif "message" in request.input:
74
+ query = request.input["message"]
75
+ else:
76
+ query = str(request.input)
77
+
78
+ # Call the chat engine
79
+ response = await self._engine.achat(query)
80
+
81
+ # Extract content from response
82
+ output = str(response.response) if hasattr(response, "response") else str(response)
83
+
84
+ return InvokeResponse(output=output)
85
+
86
+ async def chat(self, request: ChatRequest) -> ChatResponse:
87
+ """Handle a chat request.
88
+
89
+ For conversational interactions. Sends the last user message to the engine.
90
+
91
+ Args:
92
+ request: The chat request with messages.
93
+
94
+ Returns:
95
+ The chat response with output and messages.
96
+ """
97
+ # Get the last user message to send to the engine
98
+ message = self._get_last_user_message(request.messages)
99
+
100
+ # Call the chat engine
101
+ response = await self._engine.achat(message)
102
+
103
+ # Extract content from response
104
+ output = str(response.response) if hasattr(response, "response") else str(response)
105
+
106
+ # Build response messages (original + assistant response)
107
+ response_messages: list[dict[str, Any]] = [
108
+ {"role": m.role, "content": m.content} for m in request.messages
109
+ ]
110
+ response_messages.append({"role": "assistant", "content": output})
111
+
112
+ return ChatResponse(output=output, messages=response_messages)
113
+
114
+ async def invoke_stream(self, request: InvokeRequest) -> AsyncIterator[str]:
115
+ """Handle a streaming invoke request.
116
+
117
+ Args:
118
+ request: The invoke request with input data.
119
+
120
+ Yields:
121
+ JSON-encoded chunks from the stream.
122
+ """
123
+ # Extract query from input
124
+ if "query" in request.input:
125
+ query = request.input["query"]
126
+ elif "prompt" in request.input:
127
+ query = request.input["prompt"]
128
+ elif "message" in request.input:
129
+ query = request.input["message"]
130
+ else:
131
+ query = str(request.input)
132
+
133
+ # Stream from the chat engine
134
+ response = await self._engine.astream_chat(query)
135
+ async for token in response.async_response_gen():
136
+ yield json.dumps({"chunk": token})
137
+
138
+ async def chat_stream(self, request: ChatRequest) -> AsyncIterator[str]:
139
+ """Handle a streaming chat request.
140
+
141
+ Args:
142
+ request: The chat request with messages.
143
+
144
+ Yields:
145
+ JSON-encoded chunks from the stream.
146
+ """
147
+ # Get the last user message to send to the engine
148
+ message = self._get_last_user_message(request.messages)
149
+
150
+ # Stream from the chat engine
151
+ response = await self._engine.astream_chat(message)
152
+ async for token in response.async_response_gen():
153
+ yield json.dumps({"chunk": token})
154
+
155
+
156
+ def wrap(engine: ChatEngine, name: str = "llamaindex-agent") -> LlamaIndexAdapter:
157
+ """Wrap a LlamaIndex chat engine for use with Reminix Runtime.
158
+
159
+ Args:
160
+ engine: A LlamaIndex chat engine (e.g., SimpleChatEngine, ContextChatEngine).
161
+ name: Name for the agent.
162
+
163
+ Returns:
164
+ A LlamaIndexAdapter instance.
165
+
166
+ Example:
167
+ ```python
168
+ from llama_index.core.chat_engine import SimpleChatEngine
169
+ from llama_index.llms.openai import OpenAI
170
+ from reminix_llamaindex import wrap
171
+ from reminix_runtime import serve
172
+
173
+ llm = OpenAI(model="gpt-4")
174
+ engine = SimpleChatEngine.from_defaults(llm=llm)
175
+ agent = wrap(engine, name="my-agent")
176
+ serve([agent], port=8080)
177
+ ```
178
+ """
179
+ return LlamaIndexAdapter(engine, name=name)
File without changes
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: reminix-llamaindex
3
+ Version: 0.0.1
4
+ Summary: Reminix adapter for LlamaIndex
5
+ License-Expression: Apache-2.0
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: llama-index>=0.14.0
8
+ Requires-Dist: reminix-runtime~=0.0.1
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
11
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
12
+ Description-Content-Type: text/markdown
13
+
14
+ # reminix-llamaindex
15
+
16
+ Reminix Runtime adapter for [LlamaIndex](https://www.llamaindex.ai/). Deploy LlamaIndex chat engines as a REST API.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install reminix-llamaindex
22
+ ```
23
+
24
+ This will also install `reminix-runtime` as a dependency.
25
+
26
+ ## Quick Start
27
+
28
+ ```python
29
+ from llama_index.core.chat_engine import SimpleChatEngine
30
+ from llama_index.llms.openai import OpenAI
31
+ from reminix_llamaindex import wrap
32
+ from reminix_runtime import serve
33
+
34
+ # Create a LlamaIndex chat engine
35
+ llm = OpenAI(model="gpt-4o")
36
+ engine = SimpleChatEngine.from_defaults(llm=llm)
37
+
38
+ # Wrap it with the Reminix adapter
39
+ agent = wrap(engine, name="my-chatbot")
40
+
41
+ # Serve it as a REST API
42
+ serve([agent], port=8080)
43
+ ```
44
+
45
+ Your agent is now available at:
46
+ - `POST /agents/my-chatbot/invoke` - Stateless invocation
47
+ - `POST /agents/my-chatbot/chat` - Conversational chat
48
+
49
+ ## API Reference
50
+
51
+ ### `wrap(engine, name)`
52
+
53
+ Wrap a LlamaIndex chat engine for use with Reminix Runtime.
54
+
55
+ | Parameter | Type | Default | Description |
56
+ |-----------|------|---------|-------------|
57
+ | `engine` | `BaseChatEngine` | required | A LlamaIndex chat engine |
58
+ | `name` | `str` | `"llamaindex-agent"` | Name for the agent (used in URL path) |
59
+
60
+ **Returns:** `LlamaIndexAdapter` - A Reminix adapter instance
61
+
62
+ ### Example with RAG
63
+
64
+ ```python
65
+ from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
66
+ from llama_index.llms.openai import OpenAI
67
+ from reminix_llamaindex import wrap
68
+ from reminix_runtime import serve
69
+
70
+ # Load documents and create index
71
+ documents = SimpleDirectoryReader("./data").load_data()
72
+ index = VectorStoreIndex.from_documents(documents)
73
+
74
+ # Create a chat engine with the index
75
+ engine = index.as_chat_engine(llm=OpenAI(model="gpt-4o"))
76
+
77
+ # Wrap and serve
78
+ agent = wrap(engine, name="rag-chatbot")
79
+ serve([agent], port=8080)
80
+ ```
81
+
82
+ ## Endpoint Input/Output Formats
83
+
84
+ ### POST /agents/{name}/invoke
85
+
86
+ Stateless invocation for task-oriented operations.
87
+
88
+ **Request:**
89
+ ```json
90
+ {
91
+ "input": {
92
+ "query": "What is the capital of France?"
93
+ }
94
+ }
95
+ ```
96
+
97
+ Or with prompt:
98
+ ```json
99
+ {
100
+ "input": {
101
+ "prompt": "Summarize this text: ..."
102
+ }
103
+ }
104
+ ```
105
+
106
+ **Response:**
107
+ ```json
108
+ {
109
+ "output": "The capital of France is Paris."
110
+ }
111
+ ```
112
+
113
+ ### POST /agents/{name}/chat
114
+
115
+ Conversational chat. The adapter extracts the last user message.
116
+
117
+ **Request:**
118
+ ```json
119
+ {
120
+ "messages": [
121
+ {"role": "user", "content": "What is the capital of France?"}
122
+ ]
123
+ }
124
+ ```
125
+
126
+ **Response:**
127
+ ```json
128
+ {
129
+ "output": "The capital of France is Paris.",
130
+ "messages": [
131
+ {"role": "user", "content": "What is the capital of France?"},
132
+ {"role": "assistant", "content": "The capital of France is Paris."}
133
+ ]
134
+ }
135
+ ```
136
+
137
+ ## Runtime Documentation
138
+
139
+ For information about the server, endpoints, request/response formats, and more, see the [`reminix-runtime`](https://pypi.org/project/reminix-runtime/) package.
140
+
141
+ ## Links
142
+
143
+ - [GitHub Repository](https://github.com/reminix-ai/runtime-python)
144
+ - [LlamaIndex Documentation](https://docs.llamaindex.ai/)
145
+
146
+ ## License
147
+
148
+ Apache-2.0
@@ -0,0 +1,6 @@
1
+ reminix_llamaindex/__init__.py,sha256=F6k9DeJDD5-cwD0VlVNnu4aaIssuWQ2Uyp5eEGkEc84,86
2
+ reminix_llamaindex/adapter.py,sha256=7dVMR6nw8EL9A7KeavAwAvhFsKRO6pLdUIQRD6IH4UM,5691
3
+ reminix_llamaindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ reminix_llamaindex-0.0.1.dist-info/METADATA,sha256=lo4BbUew1TOMCtbBvtCepDEu56tmJu22sCOd2g3tGRM,3368
5
+ reminix_llamaindex-0.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
6
+ reminix_llamaindex-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any