deepset-mcp 0.0.2__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 (114) hide show
  1. deepset_mcp/__init__.py +0 -0
  2. deepset_mcp/agents/__init__.py +0 -0
  3. deepset_mcp/agents/debugging/__init__.py +0 -0
  4. deepset_mcp/agents/debugging/debugging_agent.py +37 -0
  5. deepset_mcp/agents/debugging/system_prompt.md +214 -0
  6. deepset_mcp/agents/generalist/__init__.py +0 -0
  7. deepset_mcp/agents/generalist/generalist_agent.py +38 -0
  8. deepset_mcp/agents/generalist/system_prompt.md +241 -0
  9. deepset_mcp/api/README.md +536 -0
  10. deepset_mcp/api/__init__.py +0 -0
  11. deepset_mcp/api/client.py +277 -0
  12. deepset_mcp/api/custom_components/__init__.py +0 -0
  13. deepset_mcp/api/custom_components/models.py +25 -0
  14. deepset_mcp/api/custom_components/protocols.py +17 -0
  15. deepset_mcp/api/custom_components/resource.py +56 -0
  16. deepset_mcp/api/exceptions.py +70 -0
  17. deepset_mcp/api/haystack_service/__init__.py +0 -0
  18. deepset_mcp/api/haystack_service/protocols.py +13 -0
  19. deepset_mcp/api/haystack_service/resource.py +55 -0
  20. deepset_mcp/api/indexes/__init__.py +0 -0
  21. deepset_mcp/api/indexes/models.py +63 -0
  22. deepset_mcp/api/indexes/protocols.py +53 -0
  23. deepset_mcp/api/indexes/resource.py +138 -0
  24. deepset_mcp/api/integrations/__init__.py +1 -0
  25. deepset_mcp/api/integrations/models.py +49 -0
  26. deepset_mcp/api/integrations/protocols.py +27 -0
  27. deepset_mcp/api/integrations/resource.py +57 -0
  28. deepset_mcp/api/pipeline/__init__.py +17 -0
  29. deepset_mcp/api/pipeline/log_level.py +9 -0
  30. deepset_mcp/api/pipeline/models.py +235 -0
  31. deepset_mcp/api/pipeline/protocols.py +83 -0
  32. deepset_mcp/api/pipeline/resource.py +378 -0
  33. deepset_mcp/api/pipeline_template/__init__.py +0 -0
  34. deepset_mcp/api/pipeline_template/models.py +56 -0
  35. deepset_mcp/api/pipeline_template/protocols.py +17 -0
  36. deepset_mcp/api/pipeline_template/resource.py +88 -0
  37. deepset_mcp/api/protocols.py +122 -0
  38. deepset_mcp/api/secrets/__init__.py +0 -0
  39. deepset_mcp/api/secrets/models.py +16 -0
  40. deepset_mcp/api/secrets/protocols.py +29 -0
  41. deepset_mcp/api/secrets/resource.py +112 -0
  42. deepset_mcp/api/shared_models.py +17 -0
  43. deepset_mcp/api/transport.py +336 -0
  44. deepset_mcp/api/user/__init__.py +0 -0
  45. deepset_mcp/api/user/protocols.py +11 -0
  46. deepset_mcp/api/user/resource.py +38 -0
  47. deepset_mcp/api/workspace/__init__.py +7 -0
  48. deepset_mcp/api/workspace/models.py +23 -0
  49. deepset_mcp/api/workspace/protocols.py +41 -0
  50. deepset_mcp/api/workspace/resource.py +94 -0
  51. deepset_mcp/benchmark/README.md +425 -0
  52. deepset_mcp/benchmark/__init__.py +1 -0
  53. deepset_mcp/benchmark/agent_configs/debugging_agent.yml +10 -0
  54. deepset_mcp/benchmark/agent_configs/generalist_agent.yml +6 -0
  55. deepset_mcp/benchmark/dp_validation_error_analysis/__init__.py +0 -0
  56. deepset_mcp/benchmark/dp_validation_error_analysis/eda.ipynb +757 -0
  57. deepset_mcp/benchmark/dp_validation_error_analysis/prepare_interaction_data.ipynb +167 -0
  58. deepset_mcp/benchmark/dp_validation_error_analysis/preprocessing_utils.py +213 -0
  59. deepset_mcp/benchmark/runner/__init__.py +0 -0
  60. deepset_mcp/benchmark/runner/agent_benchmark_runner.py +561 -0
  61. deepset_mcp/benchmark/runner/agent_loader.py +110 -0
  62. deepset_mcp/benchmark/runner/cli.py +39 -0
  63. deepset_mcp/benchmark/runner/cli_agent.py +373 -0
  64. deepset_mcp/benchmark/runner/cli_index.py +71 -0
  65. deepset_mcp/benchmark/runner/cli_pipeline.py +73 -0
  66. deepset_mcp/benchmark/runner/cli_tests.py +226 -0
  67. deepset_mcp/benchmark/runner/cli_utils.py +61 -0
  68. deepset_mcp/benchmark/runner/config.py +73 -0
  69. deepset_mcp/benchmark/runner/config_loader.py +64 -0
  70. deepset_mcp/benchmark/runner/interactive.py +140 -0
  71. deepset_mcp/benchmark/runner/models.py +203 -0
  72. deepset_mcp/benchmark/runner/repl.py +67 -0
  73. deepset_mcp/benchmark/runner/setup_actions.py +238 -0
  74. deepset_mcp/benchmark/runner/streaming.py +360 -0
  75. deepset_mcp/benchmark/runner/teardown_actions.py +196 -0
  76. deepset_mcp/benchmark/runner/tracing.py +21 -0
  77. deepset_mcp/benchmark/tasks/chat_rag_answers_wrong_format.yml +16 -0
  78. deepset_mcp/benchmark/tasks/documents_output_wrong.yml +13 -0
  79. deepset_mcp/benchmark/tasks/jinja_str_instead_of_complex_type.yml +11 -0
  80. deepset_mcp/benchmark/tasks/jinja_syntax_error.yml +11 -0
  81. deepset_mcp/benchmark/tasks/missing_output_mapping.yml +14 -0
  82. deepset_mcp/benchmark/tasks/no_query_input.yml +13 -0
  83. deepset_mcp/benchmark/tasks/pipelines/chat_agent_jinja_str.yml +141 -0
  84. deepset_mcp/benchmark/tasks/pipelines/chat_agent_jinja_syntax.yml +141 -0
  85. deepset_mcp/benchmark/tasks/pipelines/chat_rag_answers_wrong_format.yml +181 -0
  86. deepset_mcp/benchmark/tasks/pipelines/chat_rag_missing_output_mapping.yml +189 -0
  87. deepset_mcp/benchmark/tasks/pipelines/rag_documents_wrong_format.yml +193 -0
  88. deepset_mcp/benchmark/tasks/pipelines/rag_no_query_input.yml +191 -0
  89. deepset_mcp/benchmark/tasks/pipelines/standard_index.yml +167 -0
  90. deepset_mcp/initialize_embedding_model.py +12 -0
  91. deepset_mcp/main.py +133 -0
  92. deepset_mcp/prompts/deepset_copilot_prompt.md +271 -0
  93. deepset_mcp/prompts/deepset_debugging_agent.md +214 -0
  94. deepset_mcp/store.py +5 -0
  95. deepset_mcp/tool_factory.py +473 -0
  96. deepset_mcp/tools/__init__.py +0 -0
  97. deepset_mcp/tools/custom_components.py +52 -0
  98. deepset_mcp/tools/doc_search.py +83 -0
  99. deepset_mcp/tools/haystack_service.py +358 -0
  100. deepset_mcp/tools/haystack_service_models.py +97 -0
  101. deepset_mcp/tools/indexes.py +129 -0
  102. deepset_mcp/tools/model_protocol.py +16 -0
  103. deepset_mcp/tools/pipeline.py +335 -0
  104. deepset_mcp/tools/pipeline_template.py +116 -0
  105. deepset_mcp/tools/secrets.py +45 -0
  106. deepset_mcp/tools/tokonomics/__init__.py +73 -0
  107. deepset_mcp/tools/tokonomics/decorators.py +396 -0
  108. deepset_mcp/tools/tokonomics/explorer.py +347 -0
  109. deepset_mcp/tools/tokonomics/object_store.py +177 -0
  110. deepset_mcp/tools/workspace.py +61 -0
  111. deepset_mcp-0.0.2.dist-info/METADATA +288 -0
  112. deepset_mcp-0.0.2.dist-info/RECORD +114 -0
  113. deepset_mcp-0.0.2.dist-info/WHEEL +4 -0
  114. deepset_mcp-0.0.2.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,396 @@
1
+ """
2
+ Decorator factories for explorable and referenceable tools.
3
+
4
+ This module provides the @explorable and @referenceable decorators that enable
5
+ tools to store their outputs and accept reference inputs.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import inspect
11
+ from collections.abc import Callable
12
+ from functools import wraps
13
+ from types import UnionType
14
+ from typing import Any, TypeVar, Union, get_args, get_origin
15
+
16
+ from glom import GlomError, glom
17
+
18
+ from .explorer import RichExplorer
19
+ from .object_store import Explorable, ObjectRef, ObjectStore
20
+
21
+ F = TypeVar("F", bound=Callable[..., Any])
22
+
23
+
24
+ def _is_reference(value: Any) -> bool:
25
+ """Check if a value is a reference string."""
26
+ return isinstance(value, str) and ObjectRef.parse(value) is not None
27
+
28
+
29
+ def _type_allows_str(annotation: Any) -> bool:
30
+ """Check if a type annotation already allows string values."""
31
+ if annotation is str:
32
+ return True
33
+ origin = get_origin(annotation)
34
+ if origin in {Union, UnionType}:
35
+ return str in get_args(annotation)
36
+ return False
37
+
38
+
39
+ def _add_str_to_type(annotation: Any) -> Any:
40
+ """Add str to a type annotation to allow reference strings."""
41
+ if annotation is inspect.Parameter.empty:
42
+ return str
43
+ if _type_allows_str(annotation):
44
+ return annotation
45
+ return annotation | str
46
+
47
+
48
+ def _enhance_docstring_for_references(original: str, param_info: dict[str, dict[str, Any]], func_name: str) -> str:
49
+ """Add reference documentation to function docstring.
50
+
51
+ :param original: Original docstring.
52
+ :param param_info: Parameter modification info.
53
+ :param func_name: Function name for examples.
54
+ :return: Enhanced docstring.
55
+ """
56
+ if not original:
57
+ original = f"{func_name} function with reference support."
58
+
59
+ # Build the reference section
60
+ ref_section = [
61
+ "",
62
+ "**Reference Support**",
63
+ "",
64
+ "All parameters accept object references in the form ``@obj_id`` or ``@obj_id.path.to.value``.",
65
+ "",
66
+ ]
67
+
68
+ if param_info:
69
+ ref_section.append("Parameter types after decoration:")
70
+ ref_section.append("")
71
+ for name, info in param_info.items():
72
+ if info["accepts_str"]:
73
+ ref_section.append(f"- ``{name}``: {info['original']} (already accepts strings)")
74
+ else:
75
+ ref_section.append(f"- ``{name}``: {info['original']} → {info['modified']} (now accepts references)")
76
+ ref_section.append("")
77
+
78
+ ref_section.extend(
79
+ [
80
+ "Examples::",
81
+ "",
82
+ " # Direct call with values",
83
+ f" {func_name}(data={{'key': 'value'}}, threshold=10)",
84
+ "",
85
+ " # Call with references",
86
+ f" {func_name}(data='@obj_001', threshold='@obj_002.config.threshold')",
87
+ "",
88
+ " # Mixed call",
89
+ f" {func_name}(data='@obj_001.items', threshold=10)",
90
+ ]
91
+ )
92
+
93
+ return original.rstrip() + "\n" + "\n".join(ref_section)
94
+
95
+
96
+ def _enhance_docstring_for_explorable(original: str, func_name: str) -> str:
97
+ """Add explorable documentation to function docstring.
98
+
99
+ :param original: Original docstring.
100
+ :param func_name: Function name.
101
+ :return: Enhanced docstring.
102
+ """
103
+ if not original:
104
+ original = f"{func_name} function with stored output."
105
+
106
+ section = [
107
+ "",
108
+ "**Output Storage**",
109
+ "",
110
+ "The output of this function is automatically stored and can be referenced in other functions.",
111
+ "The function returns a formatted preview of the result along with an object ID (e.g., ``@obj_123``).",
112
+ "",
113
+ "Use the returned object ID to pass this result to other functions that accept references.",
114
+ ]
115
+
116
+ return original.rstrip() + "\n" + "\n".join(section)
117
+
118
+
119
+ def explorable(
120
+ *,
121
+ object_store: ObjectStore,
122
+ explorer: RichExplorer,
123
+ ) -> Callable[[F], F]:
124
+ """Decorator factory that stores function results for later reference.
125
+
126
+ :param object_store: The object store instance to use for storage.
127
+ :param explorer: The RichExplorer instance to use for previews.
128
+ :return: Decorator function.
129
+
130
+ Examples
131
+ --------
132
+ >>> store = ObjectStore()
133
+ >>> explorer = RichExplorer(store)
134
+ >>>
135
+ >>> @explorable(object_store=store, explorer=explorer)
136
+ ... def process_data(data: dict) -> dict:
137
+ ... return {"processed": data}
138
+ ...
139
+ >>> result = process_data({"input": "value"})
140
+ >>> # result contains a preview and object ID like "@obj_001"
141
+ """
142
+
143
+ def decorator(func: F) -> F:
144
+ if inspect.iscoroutinefunction(func):
145
+
146
+ @wraps(func)
147
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Explorable[Any]:
148
+ result = await func(*args, **kwargs)
149
+ obj_id = object_store.put(result)
150
+ preview = explorer.explore(obj_id)
151
+ return Explorable(obj_id, result, preview)
152
+
153
+ # Enhance docstring
154
+ async_wrapper.__doc__ = _enhance_docstring_for_explorable(func.__doc__ or "", func.__name__)
155
+ return async_wrapper # type: ignore[return-value]
156
+ else:
157
+
158
+ @wraps(func)
159
+ def sync_wrapper(*args: Any, **kwargs: Any) -> Explorable[Any]:
160
+ result = func(*args, **kwargs)
161
+ obj_id = object_store.put(result)
162
+ preview = explorer.explore(obj_id)
163
+ return Explorable(obj_id, result, preview)
164
+
165
+ # Enhance docstring
166
+ sync_wrapper.__doc__ = _enhance_docstring_for_explorable(func.__doc__ or "", func.__name__)
167
+ return sync_wrapper # type: ignore[return-value]
168
+
169
+ return decorator
170
+
171
+
172
+ def referenceable(
173
+ *,
174
+ object_store: ObjectStore,
175
+ explorer: RichExplorer,
176
+ ) -> Callable[[F], F]:
177
+ """Decorator factory that enables parameters to accept object references.
178
+
179
+ Parameters can accept reference strings like '@obj_001' or '@obj_001.path.to.value'
180
+ which are automatically resolved before calling the function.
181
+
182
+ :param object_store: The object store instance to use for lookups.
183
+ :param explorer: The RichExplorer instance to use for path validation.
184
+ :return: Decorator function.
185
+
186
+ Examples
187
+ --------
188
+ >>> store = ObjectStore()
189
+ >>> explorer = RichExplorer(store)
190
+ >>>
191
+ >>> @referenceable(object_store=store, explorer=explorer)
192
+ ... def process_data(data: dict, threshold: int) -> str:
193
+ ... return f"Processed {len(data)} items with threshold {threshold}"
194
+ ...
195
+ >>> # Call with actual values
196
+ >>> process_data({"a": 1, "b": 2}, 10)
197
+ >>>
198
+ >>> # Call with references
199
+ >>> process_data("@obj_001", "@obj_002.config.threshold")
200
+ """
201
+
202
+ def resolve_reference(ref_str: str) -> Any:
203
+ """Resolve a reference string to its actual value."""
204
+ ref = ObjectRef.parse(ref_str)
205
+ if ref is None:
206
+ raise ValueError(f"Invalid reference format: {ref_str}")
207
+
208
+ obj = object_store.get(ref.obj_id)
209
+ if obj is None:
210
+ raise ValueError(f"Object @{ref.obj_id} not found or expired")
211
+
212
+ if ref.path:
213
+ try:
214
+ explorer._validate_path(ref.path)
215
+ return glom(obj, explorer._parse_path(ref.path))
216
+ except GlomError as exc:
217
+ raise ValueError(f"Navigation error at {ref.path}: {exc}") from exc
218
+ except ValueError as exc:
219
+ raise ValueError(f"Invalid path {ref.path}: {exc}") from exc
220
+
221
+ return obj
222
+
223
+ def decorator(func: F) -> F:
224
+ sig = inspect.signature(func)
225
+
226
+ # Track which parameters need type modifications
227
+ param_info: dict[str, dict[str, Any]] = {}
228
+ new_params = []
229
+
230
+ for name, param in sig.parameters.items():
231
+ ann = param.annotation
232
+ if ann is inspect.Parameter.empty:
233
+ ann = Any
234
+
235
+ if _type_allows_str(ann):
236
+ # Already accepts strings
237
+ param_info[name] = {"original": ann, "modified": ann, "accepts_str": True}
238
+ new_params.append(param)
239
+ else:
240
+ # Add str to type union
241
+ new_ann = _add_str_to_type(ann)
242
+ param_info[name] = {"original": ann, "modified": new_ann, "accepts_str": False}
243
+ new_params.append(param.replace(annotation=new_ann))
244
+
245
+ new_sig = sig.replace(parameters=new_params)
246
+
247
+ if inspect.iscoroutinefunction(func):
248
+
249
+ @wraps(func)
250
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
251
+ # Bind arguments to get parameter names
252
+ bound = sig.bind(*args, **kwargs)
253
+ bound.apply_defaults()
254
+
255
+ # Resolve references
256
+ resolved_args = []
257
+ resolved_kwargs = {}
258
+
259
+ for name, value in bound.arguments.items():
260
+ info = param_info.get(name, {})
261
+
262
+ # Check for invalid string values
263
+ if not info.get("accepts_str", True) and isinstance(value, str):
264
+ if not _is_reference(value):
265
+ raise TypeError(
266
+ f"Parameter '{name}' expects {info['original']}, "
267
+ f"got string '{value}'. Use '@obj_id' for references."
268
+ )
269
+
270
+ # Resolve references
271
+ if _is_reference(value):
272
+ value = resolve_reference(value)
273
+
274
+ # Reconstruct args/kwargs
275
+ param = sig.parameters[name]
276
+ if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
277
+ if name in list(sig.parameters)[: len(bound.args)]:
278
+ resolved_args.append(value)
279
+ else:
280
+ resolved_kwargs[name] = value
281
+ else:
282
+ resolved_kwargs[name] = value
283
+
284
+ return await func(*resolved_args, **resolved_kwargs)
285
+
286
+ # Update signature and docstring
287
+ async_wrapper.__signature__ = new_sig # type: ignore[attr-defined]
288
+ async_wrapper.__doc__ = _enhance_docstring_for_references(func.__doc__ or "", param_info, func.__name__)
289
+ return async_wrapper # type: ignore[return-value]
290
+ else:
291
+
292
+ @wraps(func)
293
+ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
294
+ # Bind arguments to get parameter names
295
+ bound = sig.bind(*args, **kwargs)
296
+ bound.apply_defaults()
297
+
298
+ # Resolve references
299
+ resolved_args = []
300
+ resolved_kwargs = {}
301
+
302
+ for name, value in bound.arguments.items():
303
+ info = param_info.get(name, {})
304
+
305
+ # Check for invalid string values
306
+ if not info.get("accepts_str", True) and isinstance(value, str):
307
+ if not _is_reference(value):
308
+ raise TypeError(
309
+ f"Parameter '{name}' expects {info['original']}, "
310
+ f"got string '{value}'. Use '@obj_id' for references."
311
+ )
312
+
313
+ # Resolve references
314
+ if _is_reference(value):
315
+ value = resolve_reference(value)
316
+
317
+ # Reconstruct args/kwargs
318
+ param = sig.parameters[name]
319
+ if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
320
+ if name in list(sig.parameters)[: len(bound.args)]:
321
+ resolved_args.append(value)
322
+ else:
323
+ resolved_kwargs[name] = value
324
+ else:
325
+ resolved_kwargs[name] = value
326
+
327
+ return func(*resolved_args, **resolved_kwargs)
328
+
329
+ # Update signature and docstring
330
+ sync_wrapper.__signature__ = new_sig # type: ignore[attr-defined]
331
+ sync_wrapper.__doc__ = _enhance_docstring_for_references(func.__doc__ or "", param_info, func.__name__)
332
+ return sync_wrapper # type: ignore[return-value]
333
+
334
+ return decorator
335
+
336
+
337
+ def explorable_and_referenceable(
338
+ *,
339
+ object_store: ObjectStore,
340
+ explorer: RichExplorer,
341
+ ) -> Callable[[F], F]:
342
+ """Decorator factory that combines @explorable and @referenceable functionality.
343
+
344
+ The decorated function can accept reference parameters AND stores its result
345
+ in the object store for later reference.
346
+
347
+ :param object_store: The object store instance to use.
348
+ :param explorer: The RichExplorer instance to use.
349
+ :return: Decorator function.
350
+
351
+ Examples
352
+ --------
353
+ >>> store = ObjectStore()
354
+ >>> explorer = RichExplorer(store)
355
+ >>>
356
+ >>> @explorable_and_referenceable(object_store=store, explorer=explorer)
357
+ ... def merge_data(data1: dict, data2: dict) -> dict:
358
+ ... return {**data1, **data2}
359
+ ...
360
+ >>> # Accepts references and returns preview with object ID
361
+ >>> result = merge_data("@obj_001", {"new": "data"})
362
+ >>> # result contains a preview and can be referenced as "@obj_002"
363
+ """
364
+
365
+ def decorator(func: F) -> F:
366
+ # First apply referenceable to handle input references
367
+ ref_func = referenceable(object_store=object_store, explorer=explorer)(func)
368
+ # Then apply explorable to handle output storage
369
+ exp_func = explorable(object_store=object_store, explorer=explorer)(ref_func)
370
+
371
+ # Combine docstrings (remove duplicate function name line)
372
+ if ref_func.__doc__ and exp_func.__doc__:
373
+ # Take the reference part from ref_func and explorable part from exp_func
374
+ ref_lines = ref_func.__doc__.split("\n")
375
+ exp_lines = exp_func.__doc__.split("\n")
376
+
377
+ # Find where the reference section starts
378
+ ref_start = next((i for i, line in enumerate(ref_lines) if "**Reference Support**" in line), len(ref_lines))
379
+ # Find where the explorable section starts
380
+ exp_start = next((i for i, line in enumerate(exp_lines) if "**Output Storage**" in line), 0)
381
+
382
+ # Combine: original + reference section + explorable section
383
+ # Take everything from ref_func including reference section but excluding examples
384
+ # Find end of reference section (before examples)
385
+ ref_end = len(ref_lines)
386
+ for i in range(ref_start, len(ref_lines)):
387
+ if "Examples::" in ref_lines[i]:
388
+ ref_end = i
389
+ break
390
+
391
+ combined = ref_lines[:ref_end] + exp_lines[exp_start:]
392
+ exp_func.__doc__ = "\n".join(combined)
393
+
394
+ return exp_func
395
+
396
+ return decorator