prashflow 1.0.0__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 (33) hide show
  1. prashflow-1.0.0/PKG-INFO +665 -0
  2. prashflow-1.0.0/README.md +596 -0
  3. prashflow-1.0.0/pyproject.toml +69 -0
  4. prashflow-1.0.0/setup.cfg +4 -0
  5. prashflow-1.0.0/src/prashflow/__init__.py +25 -0
  6. prashflow-1.0.0/src/prashflow/__version__.py +1 -0
  7. prashflow-1.0.0/src/prashflow/agent.py +112 -0
  8. prashflow-1.0.0/src/prashflow/agentchat.py +5 -0
  9. prashflow-1.0.0/src/prashflow/chat.py +38 -0
  10. prashflow-1.0.0/src/prashflow/cli.py +43 -0
  11. prashflow-1.0.0/src/prashflow/config.py +26 -0
  12. prashflow-1.0.0/src/prashflow/display.py +14 -0
  13. prashflow-1.0.0/src/prashflow/errors.py +15 -0
  14. prashflow-1.0.0/src/prashflow/inmemory.py +87 -0
  15. prashflow-1.0.0/src/prashflow/llm.py +206 -0
  16. prashflow-1.0.0/src/prashflow/loaders.py +40 -0
  17. prashflow-1.0.0/src/prashflow/mcp.py +55 -0
  18. prashflow-1.0.0/src/prashflow/memory.py +11 -0
  19. prashflow-1.0.0/src/prashflow/multiagent.py +140 -0
  20. prashflow-1.0.0/src/prashflow/rag.py +227 -0
  21. prashflow-1.0.0/src/prashflow/rerank.py +30 -0
  22. prashflow-1.0.0/src/prashflow/retrieval.py +38 -0
  23. prashflow-1.0.0/src/prashflow/session.py +21 -0
  24. prashflow-1.0.0/src/prashflow/sql_ingest.py +70 -0
  25. prashflow-1.0.0/src/prashflow/tools.py +64 -0
  26. prashflow-1.0.0/src/prashflow/vectorstores.py +91 -0
  27. prashflow-1.0.0/src/prashflow.egg-info/PKG-INFO +665 -0
  28. prashflow-1.0.0/src/prashflow.egg-info/SOURCES.txt +31 -0
  29. prashflow-1.0.0/src/prashflow.egg-info/dependency_links.txt +1 -0
  30. prashflow-1.0.0/src/prashflow.egg-info/entry_points.txt +2 -0
  31. prashflow-1.0.0/src/prashflow.egg-info/requires.txt +72 -0
  32. prashflow-1.0.0/src/prashflow.egg-info/top_level.txt +1 -0
  33. prashflow-1.0.0/tests/test_core.py +8 -0
@@ -0,0 +1,665 @@
1
+ Metadata-Version: 2.4
2
+ Name: prashflow
3
+ Version: 1.0.0
4
+ Summary: General-purpose AI application and agent runtime with chat, RAG, tools, MCP, memory, streaming and multi-provider LLM support.
5
+ Author: Prasanth
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: pydantic>=2.7
10
+ Requires-Dist: pydantic-settings>=2.5
11
+ Requires-Dist: rich>=13.7
12
+ Requires-Dist: typer>=0.12
13
+ Requires-Dist: pyyaml>=6.0
14
+ Requires-Dist: requests>=2.32
15
+ Requires-Dist: sqlalchemy>=2.0
16
+ Requires-Dist: langchain-core>=0.3
17
+ Requires-Dist: langchain-community>=0.3
18
+ Requires-Dist: langchain-text-splitters>=0.3
19
+ Requires-Dist: langchain-chroma>=0.2
20
+ Requires-Dist: langgraph>=0.2
21
+ Requires-Dist: langchain-ollama>=0.2
22
+ Requires-Dist: chromadb>=0.5
23
+ Requires-Dist: rank-bm25>=0.2.2
24
+ Requires-Dist: pypdf>=5.0
25
+ Requires-Dist: docx2txt>=0.8
26
+ Requires-Dist: beautifulsoup4>=4.12
27
+ Requires-Dist: numpy>=1.26
28
+ Provides-Extra: openai
29
+ Requires-Dist: langchain-openai>=0.3; extra == "openai"
30
+ Provides-Extra: web
31
+ Requires-Dist: ddgs>=9.0; extra == "web"
32
+ Provides-Extra: rerank
33
+ Requires-Dist: sentence-transformers>=3.0; extra == "rerank"
34
+ Provides-Extra: qdrant
35
+ Requires-Dist: qdrant-client>=1.12; extra == "qdrant"
36
+ Requires-Dist: langchain-qdrant>=0.2; extra == "qdrant"
37
+ Provides-Extra: faiss
38
+ Requires-Dist: faiss-cpu>=1.9; extra == "faiss"
39
+ Provides-Extra: pgvector
40
+ Requires-Dist: pgvector>=0.3; extra == "pgvector"
41
+ Requires-Dist: psycopg[binary]>=3.2; extra == "pgvector"
42
+ Requires-Dist: langchain-postgres>=0.0.12; extra == "pgvector"
43
+ Provides-Extra: mcp
44
+ Requires-Dist: mcp>=1.0; extra == "mcp"
45
+ Provides-Extra: litellm
46
+ Requires-Dist: litellm>=1.70; extra == "litellm"
47
+ Provides-Extra: mysql
48
+ Requires-Dist: pymysql>=1.1; extra == "mysql"
49
+ Provides-Extra: postgres
50
+ Requires-Dist: psycopg[binary]>=3.2; extra == "postgres"
51
+ Provides-Extra: all
52
+ Requires-Dist: langchain-openai>=0.3; extra == "all"
53
+ Requires-Dist: ddgs>=9.0; extra == "all"
54
+ Requires-Dist: sentence-transformers>=3.0; extra == "all"
55
+ Requires-Dist: qdrant-client>=1.12; extra == "all"
56
+ Requires-Dist: langchain-qdrant>=0.2; extra == "all"
57
+ Requires-Dist: faiss-cpu>=1.9; extra == "all"
58
+ Requires-Dist: pgvector>=0.3; extra == "all"
59
+ Requires-Dist: psycopg[binary]>=3.2; extra == "all"
60
+ Requires-Dist: langchain-postgres>=0.0.12; extra == "all"
61
+ Requires-Dist: mcp>=1.0; extra == "all"
62
+ Requires-Dist: pymysql>=1.1; extra == "all"
63
+ Requires-Dist: litellm>=1.70; extra == "all"
64
+ Provides-Extra: dev
65
+ Requires-Dist: pytest>=8.0; extra == "dev"
66
+ Requires-Dist: ruff>=0.8; extra == "dev"
67
+ Requires-Dist: build>=1.2; extra == "dev"
68
+ Requires-Dist: twine>=6.0; extra == "dev"
69
+
70
+ # PrashFlow
71
+
72
+ **PrashFlow** is a general-purpose Python AI application and agent runtime designed to make Chat, RAG, agents, multi-agent systems, tools, MCP, memory, streaming, and multiple model providers available through a small Python API.
73
+
74
+ It is **not only a RAG library**.
75
+
76
+ ## What you can build
77
+
78
+ - Local Ollama RAG applications
79
+ - Streaming chat with user sessions
80
+ - Semantic, BM25/keyword, hybrid, MMR and multi-query retrieval
81
+ - Chroma, Qdrant, FAISS, PGVector and in-memory vector stores
82
+ - PDF/DOCX/TXT/Markdown/CSV/web ingestion
83
+ - SQL database ingestion
84
+ - Single tool-using agents with LangGraph
85
+ - Agentic Ollama chat
86
+ - Supervisor, sequential and parallel multi-agent workflows
87
+ - Custom Python tools
88
+ - Optional web search
89
+ - MCP configuration/adapter boundary
90
+ - OpenAI and OpenAI-compatible models
91
+ - LiteLLM model gateway
92
+ - Environment-variable based YAML configuration
93
+ - Retries and clear validation errors
94
+
95
+ ## Architecture
96
+
97
+ ```text
98
+ PRASHFLOW
99
+ |
100
+ +---------------------+----------------------+
101
+ | | |
102
+ Chat RAG Agent
103
+ | | |
104
+ Streaming Ingestion/Retrieval Tools
105
+ Sessions | MCP
106
+ | +-------+-------+ |
107
+ | | | | |
108
+ | Semantic BM25 MMR |
109
+ | | | | |
110
+ | +-------+-------+ |
111
+ | | |
112
+ | RRF |
113
+ | | |
114
+ | Rerank |
115
+ | | |
116
+ +----------------------+---------------------+
117
+ |
118
+ Model Layer
119
+ |
120
+ +---------+---------+
121
+ | | |
122
+ Ollama OpenAI LiteLLM
123
+ |
124
+ MultiAgent
125
+ |
126
+ +------------+------------+
127
+ | | |
128
+ Supervisor Sequential Parallel
129
+ ```
130
+
131
+ ## Installation
132
+
133
+ Basic:
134
+
135
+ ```bash
136
+ pip install prashflow
137
+ ```
138
+
139
+ All optional integrations:
140
+
141
+ ```bash
142
+ pip install "prashflow[all]"
143
+ ```
144
+
145
+ For local Ollama + Chroma RAG, the `all` extra is convenient. You can also install only the extras you need.
146
+
147
+ ## 1. Local Ollama RAG in a few lines
148
+
149
+ Put documents in `./knowledge`:
150
+
151
+ ```text
152
+ my-app/
153
+ ├── knowledge/
154
+ │ ├── deployment.pdf
155
+ │ ├── architecture.docx
156
+ │ ├── troubleshooting.txt
157
+ │ └── security.md
158
+ ├── data/
159
+ └── app.py
160
+ ```
161
+
162
+ Pull local models:
163
+
164
+ ```bash
165
+ ollama pull qwen3:8b
166
+ ollama pull nomic-embed-text
167
+ ```
168
+
169
+ Python:
170
+
171
+ ```python
172
+ from prashflow import RAG
173
+
174
+ rag = RAG(
175
+ llm="ollama:qwen3:8b",
176
+ embeddings="ollama:nomic-embed-text",
177
+ vector_db="chroma:./data/chroma",
178
+ retrieval={
179
+ "type": "hybrid",
180
+ "top_k": 5,
181
+ "candidate_k": 20,
182
+ "semantic_weight": 0.6,
183
+ "keyword_weight": 0.4,
184
+ },
185
+ )
186
+
187
+ rag.ingest("./knowledge")
188
+
189
+ print(rag.ask("What is our production deployment process?"))
190
+ ```
191
+
192
+ PrashFlow hides the LangChain, Chroma, loader and embedding implementation from the application code.
193
+
194
+ ## 2. Search algorithms
195
+
196
+ Semantic:
197
+
198
+ ```python
199
+ rag.search("production deployment", search_type="semantic")
200
+ ```
201
+
202
+ BM25/keyword:
203
+
204
+ ```python
205
+ rag.search("JIRA-12345", search_type="keyword")
206
+ ```
207
+
208
+ MMR:
209
+
210
+ ```python
211
+ rag.search("deployment architecture", search_type="mmr")
212
+ ```
213
+
214
+ Hybrid:
215
+
216
+ ```python
217
+ rag.search("production deployment", search_type="hybrid")
218
+ ```
219
+
220
+ Multi-query:
221
+
222
+ ```python
223
+ rag.search("How do we release an application?", search_type="multi_query")
224
+ ```
225
+
226
+ Hybrid combines semantic and keyword rankings with reciprocal-rank fusion. MMR adds diversity. An optional cross-encoder reranker can be enabled with the `rerank` extra.
227
+
228
+ ## 3. Persistent Chroma
229
+
230
+ ```python
231
+ rag = RAG(
232
+ llm="ollama:qwen3:8b",
233
+ embeddings="ollama:nomic-embed-text",
234
+ vector_db={
235
+ "provider": "chroma",
236
+ "path": "./data/chroma",
237
+ "collection": "company_docs",
238
+ },
239
+ )
240
+ ```
241
+
242
+ The Chroma data remains on disk after the Python process exits.
243
+
244
+ ### In-memory vector store
245
+
246
+ ```python
247
+ rag = RAG(
248
+ llm="ollama:qwen3:8b",
249
+ embeddings="ollama:nomic-embed-text",
250
+ vector_db={"provider": "memory"},
251
+ )
252
+ ```
253
+
254
+ This is intended for tests, demos and short-lived applications.
255
+
256
+ ## 4. User session + streaming RAG chat
257
+
258
+ This is the recommended API for a local RAG chatbot:
259
+
260
+ ```python
261
+ from prashflow import RAG
262
+
263
+ rag = RAG(
264
+ llm="ollama:qwen3:8b",
265
+ embeddings="ollama:nomic-embed-text",
266
+ vector_db="chroma:./data/chroma",
267
+ retrieval={"type": "hybrid", "top_k": 5},
268
+ )
269
+
270
+ rag.ingest("./knowledge")
271
+
272
+ session_id = "user-001"
273
+
274
+ while True:
275
+ question = input("You: ")
276
+ if question.lower() in {"exit", "quit"}:
277
+ break
278
+
279
+ print("AI: ", end="")
280
+ for token in rag.chat_stream(
281
+ session_id=session_id,
282
+ query=question,
283
+ search_type="hybrid",
284
+ ):
285
+ print(token, end="", flush=True)
286
+ print()
287
+ ```
288
+
289
+ The session stores conversation history independently for each `session_id`.
290
+
291
+ ```text
292
+ user-001 -> conversation A
293
+ user-002 -> conversation B
294
+ user-003 -> conversation C
295
+ ```
296
+
297
+ The default session backend is in-memory. A persistent Redis/PostgreSQL session backend can be added behind the same `SessionStore` abstraction.
298
+
299
+ ## 5. Normal Chat
300
+
301
+ ```python
302
+ from prashflow import Chat
303
+
304
+ chat = Chat(
305
+ llm="ollama:qwen3:8b",
306
+ session_id="user-001",
307
+ )
308
+
309
+ print(chat.chat("My name is Prash."))
310
+ print(chat.chat("What is my name?"))
311
+ ```
312
+
313
+ Streaming:
314
+
315
+ ```python
316
+ for token in chat.stream("Explain Kubernetes"):
317
+ print(token, end="", flush=True)
318
+ ```
319
+
320
+ ## 6. Agentic Ollama Chat
321
+
322
+ Use `AgentChat` when the model should decide when to call tools.
323
+
324
+ ```python
325
+ from prashflow import AgentChat
326
+
327
+ agent = AgentChat(
328
+ llm="ollama:qwen3:8b",
329
+ tools=["calculator"],
330
+ session_id="user-001",
331
+ )
332
+
333
+ for token in agent.stream("Calculate 25% of 8000"):
334
+ print(token, end="", flush=True)
335
+ ```
336
+
337
+ PrashFlow uses LangGraph internally for the agent loop. The application does not need to build `StateGraph` or `ToolNode` itself.
338
+
339
+ ## 7. Custom Python tools
340
+
341
+ ```python
342
+ from prashflow import Agent
343
+ def get_server_status(server: str) -> str:
344
+ """Get Linux server status."""
345
+ return f"{server}: UP"
346
+ agent = Agent(
347
+ llm={
348
+ "provider": "ollama",
349
+ "model": "qwen3:8b",
350
+ "base_url": "http://localhost:11434",
351
+ },
352
+ tools=[
353
+ "calculator",
354
+ get_server_status,
355
+ ],
356
+ )
357
+ print(
358
+ agent.run(
359
+ "Check web01 status and calculate 20 percent of 500."
360
+ )
361
+ )
362
+ ```
363
+
364
+ Tools can also require interactive approval:
365
+
366
+ ```python
367
+ @tool(requires_approval=True, max_retries=2)
368
+ def restart_service(server: str, service: str) -> str:
369
+ """Restart a Linux service."""
370
+ # implement the real operation here
371
+ return f"Restarted {service} on {server}"
372
+ ```
373
+
374
+ ## 8. Multi-agent
375
+
376
+ ### Supervisor
377
+
378
+ ```python
379
+ from prashflow import MultiAgent
380
+
381
+ team = MultiAgent(
382
+ model="ollama:qwen3:8b",
383
+ mode="supervisor",
384
+ agents=[
385
+ {
386
+ "name": "researcher",
387
+ "description": "Research technical information.",
388
+ "tools": ["web_search"],
389
+ },
390
+ {
391
+ "name": "calculator",
392
+ "description": "Perform arithmetic calculations.",
393
+ "tools": ["calculator"],
394
+ },
395
+ ],
396
+ )
397
+
398
+ print(team.run("Calculate 20% of 8000"))
399
+ ```
400
+
401
+ The supervisor chooses the specialist.
402
+
403
+ ### Sequential
404
+
405
+ ```python
406
+ team = MultiAgent(
407
+ model="ollama:qwen3:8b",
408
+ mode="sequential",
409
+ agents=[
410
+ {"name": "planner", "description": "Create a plan."},
411
+ {"name": "developer", "description": "Develop the solution."},
412
+ {"name": "reviewer", "description": "Review the solution."},
413
+ ],
414
+ )
415
+ ```
416
+
417
+ Flow:
418
+
419
+ ```text
420
+ Planner -> Developer -> Reviewer -> Final
421
+ ```
422
+
423
+ ### Parallel
424
+
425
+ ```python
426
+ team = MultiAgent(
427
+ model="ollama:qwen3:8b",
428
+ mode="parallel",
429
+ agents=[
430
+ {"name": "security", "description": "Analyze security."},
431
+ {"name": "performance", "description": "Analyze performance."},
432
+ {"name": "architecture", "description": "Analyze architecture."},
433
+ ],
434
+ )
435
+ ```
436
+
437
+ The current reference implementation runs the specialist calls independently and synthesizes their results. An async concurrent implementation can be added for high-throughput production workloads.
438
+
439
+ ### Streaming multi-agent
440
+
441
+ ```python
442
+ for token in team.stream("Analyze this deployment"):
443
+ print(token, end="", flush=True)
444
+ ```
445
+
446
+ ### Per-agent models
447
+
448
+ ```python
449
+ team = MultiAgent(
450
+ model="ollama:qwen3:8b",
451
+ agents=[
452
+ {
453
+ "name": "researcher",
454
+ "model": "ollama:qwen3:8b",
455
+ "description": "Research information.",
456
+ },
457
+ {
458
+ "name": "coder",
459
+ "model": "ollama:qwen2.5-coder:14b",
460
+ "description": "Write and review code.",
461
+ },
462
+ ],
463
+ )
464
+ ```
465
+
466
+ ## 9. RAG + Agent
467
+
468
+ ```python
469
+ from prashflow import AgentChat, RAG
470
+
471
+ rag = RAG(
472
+ llm="ollama:qwen3:8b",
473
+ embeddings="ollama:nomic-embed-text",
474
+ vector_db="chroma:./data/chroma",
475
+ retrieval={"type": "hybrid", "top_k": 5},
476
+ )
477
+ rag.ingest("./knowledge")
478
+
479
+ agent = AgentChat(
480
+ llm="ollama:qwen3:8b",
481
+ tools=[rag.as_tool(), "calculator"],
482
+ )
483
+
484
+ print(agent.run("Find our production deployment procedure."))
485
+ ```
486
+
487
+ ## 10. Multi-agent + RAG
488
+
489
+ ```python
490
+ team = MultiAgent(
491
+ model="ollama:qwen3:8b",
492
+ mode="supervisor",
493
+ agents=[
494
+ {
495
+ "name": "company_knowledge",
496
+ "description": "Answer questions from company documents.",
497
+ "tools": [rag.as_tool()],
498
+ },
499
+ {
500
+ "name": "calculator",
501
+ "description": "Perform calculations.",
502
+ "tools": ["calculator"],
503
+ },
504
+ ],
505
+ )
506
+ ```
507
+
508
+ ## 11. SQL ingestion
509
+
510
+ ```python
511
+ rag.ingest_sql(
512
+ url="postgresql+psycopg://user:password@localhost:5432/company",
513
+ query="SELECT id, title, description FROM incidents",
514
+ content_columns=["title", "description"],
515
+ metadata_columns=["id"],
516
+ )
517
+ ```
518
+
519
+ MySQL is supported through the SQLAlchemy connection URL when the MySQL extra is installed.
520
+
521
+ ## 12. MCP
522
+
523
+ PrashFlow provides an MCP configuration boundary so MCP can be attached to agents without changing the agent API.
524
+
525
+ ```python
526
+ agent = AgentChat(
527
+ llm="ollama:qwen3:8b",
528
+ mcp_servers=[
529
+ {
530
+ "name": "filesystem",
531
+ "transport": "stdio",
532
+ "command": "npx",
533
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "./workspace"],
534
+ }
535
+ ],
536
+ )
537
+ ```
538
+
539
+ The reference package validates MCP server configuration. For production MCP transport/session discovery, pin and implement against the MCP SDK version used by your organization; MCP SDK transport APIs can evolve.
540
+
541
+ ## 13. LiteLLM
542
+
543
+ ```python
544
+ from prashflow import Chat
545
+
546
+ chat = Chat(
547
+ llm={
548
+ "provider": "litellm",
549
+ "model": "openai/gpt-4.1",
550
+ }
551
+ )
552
+ ```
553
+
554
+ The application API remains `chat.chat()` / `chat.stream()` while the provider is selected by LiteLLM.
555
+
556
+ ## 14. OpenAI / OpenAI-compatible
557
+
558
+ ```python
559
+ from prashflow import Chat
560
+
561
+ chat = Chat(
562
+ llm={
563
+ "provider": "openai-compatible",
564
+ "model": "my-model",
565
+ "base_url": "http://localhost:8000/v1",
566
+ "api_key": "dummy",
567
+ }
568
+ )
569
+ ```
570
+
571
+ ## 15. YAML configuration
572
+
573
+ `prashflow.yaml`:
574
+
575
+ ```yaml
576
+ llm:
577
+ provider: ollama
578
+ model: qwen3:8b
579
+ base_url: http://localhost:11434
580
+
581
+ embeddings:
582
+ provider: ollama
583
+ model: nomic-embed-text
584
+ base_url: http://localhost:11434
585
+
586
+ vector_db:
587
+ provider: chroma
588
+ path: ./data/chroma
589
+ collection: company_docs
590
+
591
+ retrieval:
592
+ type: hybrid
593
+ top_k: 5
594
+ candidate_k: 20
595
+ semantic_weight: 0.6
596
+ keyword_weight: 0.4
597
+
598
+ chunking:
599
+ size: 1000
600
+ overlap: 200
601
+
602
+ reranker:
603
+ enabled: false
604
+ ```
605
+
606
+ Load it:
607
+
608
+ ```python
609
+ from prashflow import RAG
610
+
611
+ rag = RAG.from_config("prashflow.yaml")
612
+ ```
613
+
614
+ Environment variables are supported:
615
+
616
+ ```yaml
617
+ llm:
618
+ provider: openai
619
+ model: ${OPENAI_MODEL}
620
+ api_key: ${OPENAI_API_KEY}
621
+ ```
622
+
623
+ ## 16. Error handling
624
+
625
+ PrashFlow exposes typed exceptions:
626
+
627
+ ```python
628
+ from prashflow import PrashFlowError
629
+
630
+ try:
631
+ print(rag.ask("What is our deployment process?"))
632
+ except PrashFlowError as exc:
633
+ print(f"PrashFlow error: {exc}")
634
+ ```
635
+
636
+ Available categories include configuration, LLM, embedding, vector DB, document loading, retrieval, reranking, tool, agent and MCP errors.
637
+
638
+
639
+ ## 17. Design philosophy
640
+
641
+ Application developers should write:
642
+
643
+ ```python
644
+ from prashflow import RAG, AgentChat, MultiAgent
645
+ ```
646
+
647
+ and should not need to directly assemble LangChain loaders, LangGraph state graphs, Chroma clients, BM25 indexes, tool nodes or model-provider adapters for common use cases.
648
+
649
+ Advanced developers can still customize the underlying components when needed.
650
+
651
+ ## Roadmap
652
+
653
+ Planned production enhancements:
654
+
655
+ - true async/parallel specialist execution
656
+ - persistent Redis/PostgreSQL session backends
657
+ - complete MCP client/session discovery against a pinned SDK
658
+ - A2A support
659
+ - model fallback and cost routing
660
+ - observability/tracing
661
+ - structured output and Pydantic schemas
662
+ - FastAPI integration helpers
663
+ - ingestion manifests and changed-file detection
664
+ - background ingestion jobs
665
+ - citation objects with source/page metadata