mcp-agentic-pipelines 1.0.1

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 (119) hide show
  1. package/.env.example +93 -0
  2. package/README.md +258 -0
  3. package/package.json +70 -0
  4. package/packages/clinical/package.json +22 -0
  5. package/packages/clinical/src/index.ts +262 -0
  6. package/packages/clinical/tsconfig.json +13 -0
  7. package/packages/core/package.json +21 -0
  8. package/packages/core/src/config.ts +138 -0
  9. package/packages/core/src/errors.ts +100 -0
  10. package/packages/core/src/index.ts +104 -0
  11. package/packages/core/src/llm-config.ts +213 -0
  12. package/packages/core/src/logging.ts +66 -0
  13. package/packages/core/src/python-bridge.ts +384 -0
  14. package/packages/core/src/rate-limiter.ts +136 -0
  15. package/packages/core/src/types.ts +203 -0
  16. package/packages/core/src/validation.ts +101 -0
  17. package/packages/core/tsconfig.json +10 -0
  18. package/packages/deeppipe/package.json +21 -0
  19. package/packages/deeppipe/src/index.ts +424 -0
  20. package/packages/deeppipe/tsconfig.json +13 -0
  21. package/packages/piste/package.json +20 -0
  22. package/packages/piste/src/index.ts +48 -0
  23. package/packages/piste/tsconfig.json +13 -0
  24. package/packages/precis/package.json +20 -0
  25. package/packages/precis/src/index.ts +67 -0
  26. package/packages/precis/tsconfig.json +13 -0
  27. package/packages/server/package.json +31 -0
  28. package/packages/server/src/index.ts +427 -0
  29. package/packages/server/tsconfig.json +17 -0
  30. package/setup.mjs +141 -0
  31. package/test.mjs +337 -0
  32. package/vendors/clinical-intake/pipeline.mjs +349 -0
  33. package/vendors/clinical-intake/questions/en.txt +9 -0
  34. package/vendors/clinical-intake/questions/fr.txt +9 -0
  35. package/vendors/piste/.env.example +73 -0
  36. package/vendors/piste/app/core/__init__.py +4 -0
  37. package/vendors/piste/app/core/config.py +83 -0
  38. package/vendors/piste/app/core/debuglog.py +16 -0
  39. package/vendors/piste/app/core/middleware.py +40 -0
  40. package/vendors/piste/bridge_piste.py +301 -0
  41. package/vendors/piste/pipeline/__init__.py +4 -0
  42. package/vendors/piste/pipeline/compiler.py +68 -0
  43. package/vendors/piste/pipeline/offline/__init__.py +28 -0
  44. package/vendors/piste/pipeline/offline/verifaid_pipeline.py +247 -0
  45. package/vendors/piste/pipeline/replay.py +15 -0
  46. package/vendors/piste/pipeline/replay_engine.py +249 -0
  47. package/vendors/piste/pipeline/signatures/__init__.py +4 -0
  48. package/vendors/piste/pipeline/signatures/signatures.py +136 -0
  49. package/vendors/piste/pipeline/stage1/__init__.py +21 -0
  50. package/vendors/piste/pipeline/stage1/atomic_decomposer.py +61 -0
  51. package/vendors/piste/pipeline/stage1/check_worthiness.py +100 -0
  52. package/vendors/piste/pipeline/stage1/orchestrator.py +175 -0
  53. package/vendors/piste/pipeline/stage1/test_stage1.py +162 -0
  54. package/vendors/piste/pipeline/stage2/__init__.py +34 -0
  55. package/vendors/piste/pipeline/stage2/blind_retriever.py +303 -0
  56. package/vendors/piste/pipeline/stage2/canonical_mapper.py +124 -0
  57. package/vendors/piste/pipeline/stage2/credibility_scorer.py +85 -0
  58. package/vendors/piste/pipeline/stage2/orchestrator.py +311 -0
  59. package/vendors/piste/pipeline/stage2/query_refiner.py +88 -0
  60. package/vendors/piste/pipeline/stage2/search_decision.py +69 -0
  61. package/vendors/piste/pipeline/stage2/test_stage2.py +265 -0
  62. package/vendors/piste/pipeline/stage3/__init__.py +20 -0
  63. package/vendors/piste/pipeline/stage3/classifier.py +79 -0
  64. package/vendors/piste/pipeline/stage3/orchestrator.py +225 -0
  65. package/vendors/piste/pipeline/stage3/test_stage3.py +101 -0
  66. package/vendors/piste/pipeline/stage4/__init__.py +33 -0
  67. package/vendors/piste/pipeline/stage4/criticality_gate.py +177 -0
  68. package/vendors/piste/pipeline/stage4/orchestrator.py +269 -0
  69. package/vendors/piste/pipeline/stage4/test_stage4.py +192 -0
  70. package/vendors/piste/pipeline/stage4/verdict_aggregator.py +157 -0
  71. package/vendors/piste/requirements.txt +53 -0
  72. package/vendors/precis/backend/__init__.py +6 -0
  73. package/vendors/precis/backend/agents/__init__.py +3 -0
  74. package/vendors/precis/backend/agents/data_synthesis.py +105 -0
  75. package/vendors/precis/backend/agents/dist_free_synth.py +97 -0
  76. package/vendors/precis/backend/agents/exact_hash_retriever.py +327 -0
  77. package/vendors/precis/backend/agents/fusion_ranker.py +64 -0
  78. package/vendors/precis/backend/agents/guardrail.py +175 -0
  79. package/vendors/precis/backend/agents/query_expander.py +89 -0
  80. package/vendors/precis/backend/agents/radial_interpol.py +99 -0
  81. package/vendors/precis/backend/agents/report_generator.py +92 -0
  82. package/vendors/precis/backend/agents/semantic_reranker.py +135 -0
  83. package/vendors/precis/backend/agents/stat_anomaly.py +93 -0
  84. package/vendors/precis/backend/agents/vector_index.py +123 -0
  85. package/vendors/precis/backend/agents/veri_score.py +341 -0
  86. package/vendors/precis/backend/agents/work_order_extractor.py +205 -0
  87. package/vendors/precis/backend/api/__init__.py +3 -0
  88. package/vendors/precis/backend/api/routes/__init__.py +3 -0
  89. package/vendors/precis/backend/config.py +88 -0
  90. package/vendors/precis/backend/core/__init__.py +13 -0
  91. package/vendors/precis/backend/core/hashing.py +22 -0
  92. package/vendors/precis/backend/core/metrics.py +77 -0
  93. package/vendors/precis/backend/core/multitoken.py +166 -0
  94. package/vendors/precis/backend/core/pmi.py +54 -0
  95. package/vendors/precis/backend/core/stemming.py +74 -0
  96. package/vendors/precis/backend/core/tracing.py +150 -0
  97. package/vendors/precis/backend/data/__init__.py +3 -0
  98. package/vendors/precis/backend/data/chunker.py +57 -0
  99. package/vendors/precis/backend/data/pdf_parser.py +42 -0
  100. package/vendors/precis/backend/db/__init__.py +3 -0
  101. package/vendors/precis/backend/db/models.py +173 -0
  102. package/vendors/precis/backend/db/repository.py +269 -0
  103. package/vendors/precis/backend/llm/__init__.py +3 -0
  104. package/vendors/precis/backend/llm/anthropic_provider.py +39 -0
  105. package/vendors/precis/backend/llm/base.py +147 -0
  106. package/vendors/precis/backend/llm/deepseek_provider.py +43 -0
  107. package/vendors/precis/backend/llm/factory.py +60 -0
  108. package/vendors/precis/backend/llm/google_provider.py +39 -0
  109. package/vendors/precis/backend/llm/ollama_provider.py +54 -0
  110. package/vendors/precis/backend/llm/openai_provider.py +50 -0
  111. package/vendors/precis/backend/main.py +677 -0
  112. package/vendors/precis/backend/orchestrator/__init__.py +3 -0
  113. package/vendors/precis/backend/orchestrator/planner.py +81 -0
  114. package/vendors/precis/backend/orchestrator/router.py +319 -0
  115. package/vendors/precis/backend/orchestrator/types.py +58 -0
  116. package/vendors/precis/bridge_precis.py +185 -0
  117. package/vendors/precis/data/sample_reports/README.md +8 -0
  118. package/vendors/precis/data/seed_data.py +115 -0
  119. package/vendors/precis/requirements.txt +19 -0
@@ -0,0 +1,60 @@
1
+ """© JINAN KORDAB — 2026 AI HYBRID AGENTIC RETRIEVAL-AUGMENTED GENERATION RAG PIPELINE - PERSONAL PROJECT"""
2
+
3
+ from typing import Dict, Optional, Type
4
+ from backend.llm.base import LLMProvider
5
+ from backend.config import settings
6
+
7
+
8
+ class LLMFactory:
9
+ """Central registry for LLM providers. Hot-swap by changing config."""
10
+
11
+ _providers: Dict[str, Type[LLMProvider]] = {}
12
+
13
+ @classmethod
14
+ def register(cls, name: str, provider_class: Type[LLMProvider]) -> None:
15
+ """Register a provider class. Called at startup for all 5 providers."""
16
+ cls._providers[name] = provider_class
17
+
18
+ @classmethod
19
+ def create(cls, name: str, **kwargs) -> LLMProvider:
20
+ """Create a provider instance by name. Raises ValueError if unknown."""
21
+ provider_class = cls._providers.get(name)
22
+ if provider_class is None:
23
+ available = list(cls._providers.keys())
24
+ raise ValueError(f"Unknown provider '{name}'. Available: {available}")
25
+ api_keys = {
26
+ "openai": settings.OPENAI_API_KEY, "anthropic": settings.ANTHROPIC_API_KEY,
27
+ "google": settings.GOOGLE_API_KEY, "deepseek": settings.DEEPSEEK_API_KEY,
28
+ }
29
+ api_key = api_keys.get(name)
30
+ if api_key and name != "ollama" and "api_key" not in kwargs:
31
+ return provider_class(api_key=api_key, **kwargs)
32
+ return provider_class(**kwargs)
33
+
34
+ @classmethod
35
+ def create_default(cls) -> LLMProvider:
36
+ """Create the default provider from config. Falls back to first available."""
37
+ name = settings.DEFAULT_LLM_PROVIDER
38
+ if name in cls._providers:
39
+ try:
40
+ return cls.create(name)
41
+ except Exception:
42
+ pass
43
+ for fallback in cls._providers:
44
+ try:
45
+ return cls.create(fallback)
46
+ except Exception:
47
+ continue
48
+ raise RuntimeError(f"No LLM provider available. Registered: {list(cls._providers.keys())}")
49
+
50
+ @classmethod
51
+ def create_with_fallback(cls, primary: str = "openai", fallback: str = "ollama") -> LLMProvider:
52
+ """Create primary provider, with automatic fallback on failure."""
53
+ try:
54
+ return cls.create(primary)
55
+ except Exception:
56
+ return cls.create(fallback)
57
+
58
+ @classmethod
59
+ def list_available(cls) -> list:
60
+ return list(cls._providers.keys())
@@ -0,0 +1,39 @@
1
+ """© JINAN KORDAB — 2026 AI HYBRID AGENTIC RETRIEVAL-AUGMENTED GENERATION RAG PIPELINE - PERSONAL PROJECT"""
2
+
3
+ import asyncio
4
+ from typing import AsyncGenerator, List, Optional
5
+ import google.generativeai as genai
6
+ from backend.llm.base import LLMProvider
7
+
8
+
9
+ class GoogleProvider(LLMProvider):
10
+ def __init__(self, api_key: str, model: str = "gemini-1.5-pro") -> None:
11
+ genai.configure(api_key=api_key)
12
+ self._model_name = model
13
+ self._model = genai.GenerativeModel(self._model_name)
14
+
15
+ async def generate(self, prompt: str, system_prompt: Optional[str] = None,
16
+ temperature: float = 0.7, max_tokens: int = 4096, **kwargs) -> str:
17
+ model = genai.GenerativeModel(self._model_name, system_instruction=system_prompt or None)
18
+ resp = await asyncio.to_thread(model.generate_content, prompt,
19
+ generation_config={"temperature": temperature, "max_output_tokens": max_tokens})
20
+ return resp.text or ""
21
+
22
+ async def generate_stream(self, prompt: str, system_prompt: Optional[str] = None,
23
+ temperature: float = 0.7, max_tokens: int = 4096, **kwargs) -> AsyncGenerator[str, None]:
24
+ model = genai.GenerativeModel(self._model_name, system_instruction=system_prompt or None)
25
+ resp = await asyncio.to_thread(model.generate_content, prompt, stream=True,
26
+ generation_config={"temperature": temperature, "max_output_tokens": max_tokens})
27
+ for chunk in resp:
28
+ if chunk.text:
29
+ yield chunk.text
30
+
31
+ async def embed(self, texts: List[str], model: Optional[str] = None) -> List[List[float]]:
32
+ result = await asyncio.to_thread(genai.embed_content,
33
+ model=model or "models/text-embedding-004", content=texts)
34
+ return result.get("embedding", [[0.0]])
35
+
36
+ def get_model_name(self) -> str: return self._model_name
37
+
38
+ def get_token_count(self, text: str) -> int:
39
+ return self._model.count_tokens(text).total_tokens
@@ -0,0 +1,54 @@
1
+ """© JINAN KORDAB — 2026 AI HYBRID AGENTIC RETRIEVAL-AUGMENTED GENERATION RAG PIPELINE - PERSONAL PROJECT"""
2
+
3
+ import json
4
+ from typing import AsyncGenerator, List, Optional
5
+ import httpx
6
+ from backend.llm.base import LLMProvider
7
+
8
+
9
+ class OllamaProvider(LLMProvider):
10
+ def __init__(self, base_url: str = "http://localhost:11434", model: str = "llama3") -> None:
11
+ self._base = base_url.rstrip("/")
12
+ self._model = model
13
+
14
+ async def _post(self, endpoint: str, data: dict) -> dict:
15
+ async with httpx.AsyncClient(timeout=120) as client:
16
+ resp = await client.post(f"{self._base}/api/{endpoint}", json=data)
17
+ return resp.json() if resp.status_code == 200 else {}
18
+
19
+ async def generate(self, prompt: str, system_prompt: Optional[str] = None,
20
+ temperature: float = 0.7, max_tokens: int = 4096, **kwargs) -> str:
21
+ data = {"model": self._model, "prompt": prompt, "stream": False,
22
+ "options": {"temperature": temperature, "num_predict": max_tokens}}
23
+ if system_prompt:
24
+ data["system"] = system_prompt
25
+ result = await self._post("generate", data)
26
+ return result.get("response", "")
27
+
28
+ async def generate_stream(self, prompt: str, system_prompt: Optional[str] = None,
29
+ temperature: float = 0.7, max_tokens: int = 4096, **kwargs) -> AsyncGenerator[str, None]:
30
+ data = {"model": self._model, "prompt": prompt, "stream": True,
31
+ "options": {"temperature": temperature, "num_predict": max_tokens}}
32
+ if system_prompt:
33
+ data["system"] = system_prompt
34
+ async with httpx.AsyncClient(timeout=300) as client:
35
+ async with client.stream("POST", f"{self._base}/api/generate", json=data) as resp:
36
+ async for line in resp.aiter_lines():
37
+ if line:
38
+ try:
39
+ chunk = json.loads(line)
40
+ if chunk.get("response"):
41
+ yield chunk["response"]
42
+ except json.JSONDecodeError:
43
+ pass
44
+
45
+ async def embed(self, texts: List[str], model: Optional[str] = None) -> List[List[float]]:
46
+ embeddings = []
47
+ for text in texts:
48
+ result = await self._post("embeddings", {"model": model or "nomic-embed-text", "prompt": text})
49
+ embeddings.append(result.get("embedding", [0.0]))
50
+ return embeddings
51
+
52
+ def get_model_name(self) -> str: return self._model
53
+
54
+ def get_token_count(self, text: str) -> int: return len(text) // 4
@@ -0,0 +1,50 @@
1
+ """© JINAN KORDAB — 2026 AI HYBRID AGENTIC RETRIEVAL-AUGMENTED GENERATION RAG PIPELINE - PERSONAL PROJECT"""
2
+
3
+ from typing import AsyncGenerator, List, Optional
4
+ from openai import AsyncOpenAI
5
+ from backend.llm.base import LLMProvider
6
+
7
+
8
+ class OpenAIProvider(LLMProvider):
9
+ def __init__(self, api_key: str, model: str = "gpt-4o", base_url: str = None) -> None:
10
+ self._client = AsyncOpenAI(api_key=api_key, base_url=base_url)
11
+ self._model = model
12
+
13
+ async def generate(self, prompt: str, system_prompt: Optional[str] = None,
14
+ temperature: float = 0.7, max_tokens: int = 4096, **kwargs) -> str:
15
+ messages = []
16
+ if system_prompt:
17
+ messages.append({"role": "system", "content": system_prompt})
18
+ messages.append({"role": "user", "content": prompt})
19
+ resp = await self._client.chat.completions.create(
20
+ model=self._model, messages=messages, temperature=temperature,
21
+ max_tokens=max_tokens, **kwargs)
22
+ return resp.choices[0].message.content or ""
23
+
24
+ async def generate_stream(self, prompt: str, system_prompt: Optional[str] = None,
25
+ temperature: float = 0.7, max_tokens: int = 4096, **kwargs) -> AsyncGenerator[str, None]:
26
+ messages = []
27
+ if system_prompt:
28
+ messages.append({"role": "system", "content": system_prompt})
29
+ messages.append({"role": "user", "content": prompt})
30
+ stream = await self._client.chat.completions.create(
31
+ model=self._model, messages=messages, temperature=temperature,
32
+ max_tokens=max_tokens, stream=True, **kwargs)
33
+ async for chunk in stream:
34
+ if chunk.choices[0].delta.content:
35
+ yield chunk.choices[0].delta.content
36
+
37
+ async def embed(self, texts: List[str], model: Optional[str] = None) -> List[List[float]]:
38
+ resp = await self._client.embeddings.create(
39
+ model=model or "text-embedding-3-small", input=texts)
40
+ return [d.embedding for d in resp.data]
41
+
42
+ def get_model_name(self) -> str: return self._model
43
+
44
+ def get_token_count(self, text: str) -> int:
45
+ try:
46
+ import tiktoken
47
+ enc = tiktoken.encoding_for_model(self._model)
48
+ return len(enc.encode(text))
49
+ except Exception:
50
+ return len(text) // 4