arclith-cli 0.18.0__tar.gz → 0.20.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 (53) hide show
  1. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/PKG-INFO +2 -2
  2. arclith_cli-0.20.0/arclith_cli/__init__.py +1 -0
  3. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/adapter_templates.py +2 -1
  4. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/capabilities.py +12 -1
  5. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/capability_models.py +41 -0
  6. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/ai.py +89 -0
  7. arclith_cli-0.20.0/arclith_cli/catalogs/channels.py +197 -0
  8. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/persistence.py +141 -0
  9. arclith_cli-0.20.0/arclith_cli/catalogs/repository_facets.py +94 -0
  10. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/init_project.py +1 -1
  11. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/main.py +1 -1
  12. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/project_paths.py +18 -3
  13. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/pyproject.toml +2 -2
  14. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/e2e_manual.sh +1 -1
  15. arclith_cli-0.20.0/tests/test_adapter_templates.py +20 -0
  16. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_add_adapter.py +166 -7
  17. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_capabilities.py +174 -0
  18. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_core_scaffold.py +1 -1
  19. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_embedding_capability.py +125 -3
  20. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_project_paths.py +1 -0
  21. arclith_cli-0.20.0/tests/test_vector_store_capability.py +166 -0
  22. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/uv.lock +6 -3
  23. arclith_cli-0.18.0/arclith_cli/__init__.py +0 -1
  24. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/.gitignore +0 -0
  25. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/LICENSE +0 -0
  26. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/Makefile +0 -0
  27. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/README.md +0 -0
  28. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/adapter_config.py +0 -0
  29. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/adapter_generator.py +0 -0
  30. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/adapter_parameters.py +0 -0
  31. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/adapter_rendering.py +0 -0
  32. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/adapter_selection.py +0 -0
  33. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/add_adapter.py +0 -0
  34. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/__init__.py +0 -0
  35. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/core.py +0 -0
  36. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/observability.py +0 -0
  37. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/security.py +0 -0
  38. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/catalogs/transports.py +0 -0
  39. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/core_scaffold.py +0 -0
  40. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/entity_scanner.py +0 -0
  41. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/export_config.py +0 -0
  42. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/new_project.py +0 -0
  43. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/recipe.py +0 -0
  44. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/recipe_cli.py +0 -0
  45. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/recipe_models.py +0 -0
  46. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/rename.py +0 -0
  47. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/runtime_templates.py +0 -0
  48. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/scaffold.py +0 -0
  49. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/arclith_cli/updater.py +0 -0
  50. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/__init__.py +0 -0
  51. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_e2e_scaffold.py +0 -0
  52. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_recipe.py +0 -0
  53. {arclith_cli-0.18.0 → arclith_cli-0.20.0}/tests/test_rename.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: arclith-cli
3
- Version: 0.18.0
3
+ Version: 0.20.0
4
4
  Summary: CLI scaffolding tool for arclith — hexagonal architecture framework
5
5
  Author-email: Killian KOPP <killiankopp@gmail.com>
6
6
  License: Apache License
@@ -186,7 +186,7 @@ License: Apache License
186
186
  License-File: LICENSE
187
187
  Keywords: arclith,cli,ddd,hexagonal-architecture,scaffold
188
188
  Requires-Python: >=3.13
189
- Requires-Dist: arclith>=0.21.0
189
+ Requires-Dist: arclith>=0.23.0
190
190
  Requires-Dist: httpx>=0.27.0
191
191
  Requires-Dist: rich>=13.0.0
192
192
  Requires-Dist: typer>=0.15.0
@@ -0,0 +1 @@
1
+ __version__ = "0.20.0"
@@ -205,7 +205,8 @@ _repository_registry: RepositoryRegistry[{pascal}, {pascal}Repository] = (
205
205
 
206
206
 
207
207
  def build_{snake}_service(arclith: Arclith) -> tuple[{pascal}Service, Logger]:
208
- arclith.logger.info("🗄️ Repository adapter selected", adapter=arclith.config.adapters.repository)
208
+ adapter = arclith.config.adapters.repository_adapter_for({pascal})
209
+ arclith.logger.info("🗄️ Repository adapter selected", adapter=adapter)
209
210
  repo: {pascal}Repository = arclith.repository({pascal}, registry=_repository_registry)
210
211
  return {pascal}Service(repo, arclith.logger, arclith.config.soft_delete.retention_days), arclith.logger
211
212
  """
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from arclith_cli.capability_models import (
6
+ AdapterFacets,
6
7
  AdapterProfileSpec,
7
8
  AdapterSpec,
8
9
  CapabilitySpec,
@@ -18,13 +19,18 @@ from arclith_cli.catalogs.ai import (
18
19
  EMBEDDING_CAPABILITY,
19
20
  LLM_CAPABILITY,
20
21
  )
22
+ from arclith_cli.catalogs.channels import CHANNEL_CAPABILITY
21
23
  from arclith_cli.catalogs.core import (
22
24
  CACHE_CAPABILITY,
23
25
  LOGGER_CAPABILITY,
24
26
  SECRETS_CAPABILITY,
25
27
  )
26
28
  from arclith_cli.catalogs.observability import OBSERVABILITY_CAPABILITY
27
- from arclith_cli.catalogs.persistence import REPOSITORY_CAPABILITY, STORAGE_CAPABILITY
29
+ from arclith_cli.catalogs.persistence import (
30
+ REPOSITORY_CAPABILITY,
31
+ STORAGE_CAPABILITY,
32
+ VECTOR_STORE_CAPABILITY,
33
+ )
28
34
  from arclith_cli.catalogs.security import (
29
35
  AUTH_CAPABILITY,
30
36
  LICENSE_CAPABILITY,
@@ -44,9 +50,11 @@ __all__ = [
44
50
  "AGENT_PERSISTENCE_CAPABILITY",
45
51
  "API_CAPABILITY",
46
52
  "AUTH_CAPABILITY",
53
+ "AdapterFacets",
47
54
  "AdapterProfileSpec",
48
55
  "AdapterSpec",
49
56
  "CACHE_CAPABILITY",
57
+ "CHANNEL_CAPABILITY",
50
58
  "CAPABILITY_CATALOG",
51
59
  "COMMAND_BUS_CAPABILITY",
52
60
  "CapabilitySpec",
@@ -68,6 +76,7 @@ __all__ = [
68
76
  "STORAGE_CAPABILITY",
69
77
  "SecretMappingSpec",
70
78
  "TENANT_CAPABILITY",
79
+ "VECTOR_STORE_CAPABILITY",
71
80
  "capability_catalog_as_dict",
72
81
  "capability_names",
73
82
  "get_capability",
@@ -77,6 +86,7 @@ __all__ = [
77
86
  CAPABILITY_CATALOG = (
78
87
  REPOSITORY_CAPABILITY,
79
88
  STORAGE_CAPABILITY,
89
+ VECTOR_STORE_CAPABILITY,
80
90
  CACHE_CAPABILITY,
81
91
  LOGGER_CAPABILITY,
82
92
  SECRETS_CAPABILITY,
@@ -85,6 +95,7 @@ CAPABILITY_CATALOG = (
85
95
  PROBE_CAPABILITY,
86
96
  HTTP_CAPABILITY,
87
97
  COMMAND_BUS_CAPABILITY,
98
+ CHANNEL_CAPABILITY,
88
99
  RUNTIME_CAPABILITY,
89
100
  AUTH_CAPABILITY,
90
101
  TENANT_CAPABILITY,
@@ -5,6 +5,16 @@ from typing import Any, Literal
5
5
 
6
6
  ParameterKind = Literal["string", "boolean"]
7
7
  LayerKind = Literal["inbound", "outbound", "bidirectional", "runtime"]
8
+ StorageModel = Literal[
9
+ "memory",
10
+ "document",
11
+ "relational_json",
12
+ "embedded_analytics",
13
+ "relational_structured",
14
+ ]
15
+ RuntimeKind = Literal["in_process", "file", "server"]
16
+ TransactionSupport = Literal["none", "limited", "strong"]
17
+ SchemaStrategy = Literal["flexible", "json_table", "structured_tables"]
8
18
 
9
19
 
10
20
  @dataclass(frozen=True)
@@ -70,6 +80,30 @@ class AdapterProfileSpec:
70
80
  return {"name": self.name, "parameters": dict(self.parameters)}
71
81
 
72
82
 
83
+ @dataclass(frozen=True)
84
+ class AdapterFacets:
85
+ storage_model: StorageModel
86
+ runtime: RuntimeKind
87
+ production_ready: bool
88
+ multi_process: bool
89
+ transactions: TransactionSupport
90
+ schema_strategy: SchemaStrategy
91
+ recommended_for: tuple[str, ...]
92
+ limits: tuple[str, ...]
93
+
94
+ def to_dict(self) -> dict[str, Any]:
95
+ return {
96
+ "storage_model": self.storage_model,
97
+ "runtime": self.runtime,
98
+ "production_ready": self.production_ready,
99
+ "multi_process": self.multi_process,
100
+ "transactions": self.transactions,
101
+ "schema_strategy": self.schema_strategy,
102
+ "recommended_for": list(self.recommended_for),
103
+ "limits": list(self.limits),
104
+ }
105
+
106
+
73
107
  @dataclass(frozen=True)
74
108
  class AdapterSpec:
75
109
  name: str
@@ -90,6 +124,7 @@ class AdapterSpec:
90
124
  profiles: tuple[AdapterProfileSpec, ...] = ()
91
125
  dependency_extra: str | None = None
92
126
  entity_scoped: bool = True
127
+ facets: AdapterFacets | None = None
93
128
 
94
129
  def has_config(self) -> bool:
95
130
  return self.config_path is not None and bool(self.config_template)
@@ -137,6 +172,7 @@ class AdapterSpec:
137
172
  "profiles": [profile.to_dict() for profile in self.profiles],
138
173
  "dependency_extra": self.dependency_extra,
139
174
  "entity_scoped": self.entity_scoped,
175
+ "facets": self.facets.to_dict() if self.facets is not None else None,
140
176
  }
141
177
 
142
178
 
@@ -169,6 +205,7 @@ class CapabilitySpec:
169
205
 
170
206
 
171
207
  __all__ = [
208
+ "AdapterFacets",
172
209
  "AdapterProfileSpec",
173
210
  "AdapterSpec",
174
211
  "CapabilitySpec",
@@ -176,5 +213,9 @@ __all__ = [
176
213
  "LayerKind",
177
214
  "ParameterKind",
178
215
  "ParameterSpec",
216
+ "RuntimeKind",
217
+ "SchemaStrategy",
179
218
  "SecretMappingSpec",
219
+ "StorageModel",
220
+ "TransactionSupport",
180
221
  ]
@@ -260,6 +260,95 @@ multitenant: {multitenant}
260
260
  dependency_extra="embedding",
261
261
  entity_scoped=False,
262
262
  ),
263
+ AdapterSpec(
264
+ name="openai",
265
+ capability="embedding",
266
+ layer="outbound",
267
+ description="Embeddings via l'API OpenAI officielle et un secret externe.",
268
+ config_path="config/adapters/outbound/embedding.yaml",
269
+ config_template="""\
270
+ adapter: openai
271
+ base_url: "{base_url}"
272
+ api_key: null
273
+ model_name: "{model_name}"
274
+ dimensions: {dimensions}
275
+ batch_size: {batch_size}
276
+ timeout: {timeout}
277
+ encoding_format: {encoding_format}
278
+ normalize: {normalize}
279
+ multitenant: {multitenant}
280
+ """,
281
+ env_path=".env",
282
+ env_template="""\
283
+ OPENAI_API_KEY={api_key}
284
+ """,
285
+ secret_mappings=(
286
+ SecretMappingSpec(
287
+ field_path="adapters.embedding.api_key",
288
+ secret_key="OPENAI_API_KEY",
289
+ ),
290
+ ),
291
+ parameters=(
292
+ ParameterSpec(
293
+ name="base_url",
294
+ kind="string",
295
+ prompt="Endpoint officiel OpenAI avec préfixe API",
296
+ default="https://api.openai.com/v1",
297
+ ),
298
+ ParameterSpec(
299
+ name="api_key",
300
+ kind="string",
301
+ prompt="OPENAI_API_KEY (laisser vide pour un secret externe)",
302
+ default="",
303
+ secret=True,
304
+ ),
305
+ ParameterSpec(
306
+ name="model_name",
307
+ kind="string",
308
+ prompt="ID du modèle d'embedding OpenAI accessible au projet",
309
+ default="remplacer-par-model-id-openai-embedding",
310
+ ),
311
+ ParameterSpec(
312
+ name="dimensions",
313
+ kind="string",
314
+ prompt="Dimension optionnelle des vecteurs (null pour le défaut modèle)",
315
+ default="null",
316
+ ),
317
+ ParameterSpec(
318
+ name="batch_size",
319
+ kind="string",
320
+ prompt="Taille maximale des sous-batches",
321
+ default="64",
322
+ ),
323
+ ParameterSpec(
324
+ name="timeout",
325
+ kind="string",
326
+ prompt="Timeout HTTP en secondes",
327
+ default="30.0",
328
+ ),
329
+ ParameterSpec(
330
+ name="encoding_format",
331
+ kind="string",
332
+ prompt="Format des vecteurs retournés",
333
+ default="float",
334
+ choices=("float",),
335
+ ),
336
+ ParameterSpec(
337
+ name="normalize",
338
+ kind="boolean",
339
+ prompt="Normaliser les vecteurs en norme L2",
340
+ default=False,
341
+ ),
342
+ ParameterSpec(
343
+ name="multitenant",
344
+ kind="boolean",
345
+ prompt="Réserver la résolution de contexte par tenant",
346
+ default=False,
347
+ ),
348
+ ),
349
+ dependency_extra="embedding",
350
+ entity_scoped=False,
351
+ ),
263
352
  ),
264
353
  )
265
354
 
@@ -0,0 +1,197 @@
1
+ from arclith_cli.capability_models import (
2
+ AdapterSpec,
3
+ CapabilitySpec,
4
+ ParameterSpec,
5
+ SecretMappingSpec,
6
+ )
7
+
8
+ CHANNEL_CAPABILITY = CapabilitySpec(
9
+ name="channel",
10
+ layer="bidirectional",
11
+ description="Messages conversationnels entrants et sortants normalisés.",
12
+ activation_config_key=None,
13
+ adapters=(
14
+ AdapterSpec(
15
+ name="memory",
16
+ capability="channel",
17
+ layer="bidirectional",
18
+ description="Fake déterministe en mémoire pour tests et prototypes locaux.",
19
+ config_path="config/adapters/bidirectional/memory.yaml",
20
+ config_template="""\
21
+ enabled: true
22
+ """,
23
+ entity_scoped=False,
24
+ ),
25
+ AdapterSpec(
26
+ name="webhook",
27
+ capability="channel",
28
+ layer="bidirectional",
29
+ description="Webhook HTTP générique signé, idempotent et provider-neutral.",
30
+ config_path="config/adapters/bidirectional/webhook.yaml",
31
+ config_template="""\
32
+ enabled: true
33
+ path: "{path}"
34
+ secret: null
35
+ signature_header: "{signature_header}"
36
+ timestamp_header: "{timestamp_header}"
37
+ signature_tolerance_seconds: {signature_tolerance_seconds}
38
+ idempotency_header: "{idempotency_header}"
39
+ event_ttl_seconds: {event_ttl_seconds}
40
+ max_payload_bytes: {max_payload_bytes}
41
+ metadata_allowlist: []
42
+ response_mode: "{response_mode}"
43
+ callback_url: {callback_url}
44
+ callback_allowed_host: {callback_allowed_host}
45
+ callback_timeout_seconds: {callback_timeout_seconds}
46
+ """,
47
+ secret_mappings=(
48
+ SecretMappingSpec(
49
+ field_path="adapters.channel.webhook.secret",
50
+ secret_key="ARCLITH_WEBHOOK_SECRET",
51
+ ),
52
+ ),
53
+ parameters=(
54
+ ParameterSpec(
55
+ name="path",
56
+ kind="string",
57
+ prompt="Route HTTP statique du webhook",
58
+ default="/channels/webhook",
59
+ ),
60
+ ParameterSpec(
61
+ name="signature_header",
62
+ kind="string",
63
+ prompt="Header de signature HMAC",
64
+ default="X-Arclith-Signature",
65
+ ),
66
+ ParameterSpec(
67
+ name="timestamp_header",
68
+ kind="string",
69
+ prompt="Header du timestamp signé",
70
+ default="X-Arclith-Timestamp",
71
+ ),
72
+ ParameterSpec(
73
+ name="signature_tolerance_seconds",
74
+ kind="string",
75
+ prompt="Tolérance de fraîcheur HMAC en secondes",
76
+ default="300",
77
+ ),
78
+ ParameterSpec(
79
+ name="idempotency_header",
80
+ kind="string",
81
+ prompt="Header de l'identifiant stable de l'événement",
82
+ default="X-Arclith-Event-Id",
83
+ ),
84
+ ParameterSpec(
85
+ name="event_ttl_seconds",
86
+ kind="string",
87
+ prompt="Durée de déduplication en secondes",
88
+ default="86400",
89
+ ),
90
+ ParameterSpec(
91
+ name="max_payload_bytes",
92
+ kind="string",
93
+ prompt="Taille maximale du payload en octets",
94
+ default="1048576",
95
+ ),
96
+ ParameterSpec(
97
+ name="response_mode",
98
+ kind="string",
99
+ prompt="Mode de réponse HTTP",
100
+ default="sync",
101
+ choices=("sync", "accepted", "callback"),
102
+ ),
103
+ ParameterSpec(
104
+ name="callback_url",
105
+ kind="string",
106
+ prompt="URL HTTPS du callback côté serveur (null hors mode callback)",
107
+ default="null",
108
+ ),
109
+ ParameterSpec(
110
+ name="callback_allowed_host",
111
+ kind="string",
112
+ prompt="Hostname exact autorisé pour le callback (null hors mode callback)",
113
+ default="null",
114
+ ),
115
+ ParameterSpec(
116
+ name="callback_timeout_seconds",
117
+ kind="string",
118
+ prompt="Timeout du callback sortant en secondes",
119
+ default="5.0",
120
+ ),
121
+ ),
122
+ dependency_extra="channel",
123
+ entity_scoped=False,
124
+ ),
125
+ AdapterSpec(
126
+ name="slack",
127
+ capability="channel",
128
+ layer="bidirectional",
129
+ description="Slack Events API signé avec réponses chat.postMessage.",
130
+ config_path="config/adapters/bidirectional/slack.yaml",
131
+ config_template="""\
132
+ enabled: true
133
+ path: "{path}"
134
+ signing_secret: null
135
+ bot_token: null
136
+ workspace_id: {workspace_id}
137
+ allowed_channel_ids: []
138
+ signature_tolerance_seconds: {signature_tolerance_seconds}
139
+ event_ttl_seconds: {event_ttl_seconds}
140
+ max_payload_bytes: {max_payload_bytes}
141
+ request_timeout_seconds: {request_timeout_seconds}
142
+ """,
143
+ secret_mappings=(
144
+ SecretMappingSpec(
145
+ field_path="adapters.channel.slack.signing_secret",
146
+ secret_key="ARCLITH_SLACK_SIGNING_SECRET",
147
+ ),
148
+ SecretMappingSpec(
149
+ field_path="adapters.channel.slack.bot_token",
150
+ secret_key="ARCLITH_SLACK_BOT_TOKEN",
151
+ ),
152
+ ),
153
+ parameters=(
154
+ ParameterSpec(
155
+ name="path",
156
+ kind="string",
157
+ prompt="Route HTTP statique des événements Slack",
158
+ default="/channels/slack/events",
159
+ ),
160
+ ParameterSpec(
161
+ name="workspace_id",
162
+ kind="string",
163
+ prompt="Workspace Slack exact autorisé (null pour tout accepter)",
164
+ default="null",
165
+ ),
166
+ ParameterSpec(
167
+ name="signature_tolerance_seconds",
168
+ kind="string",
169
+ prompt="Tolérance de fraîcheur de signature en secondes",
170
+ default="300",
171
+ ),
172
+ ParameterSpec(
173
+ name="event_ttl_seconds",
174
+ kind="string",
175
+ prompt="Durée de déduplication des event_id en secondes",
176
+ default="86400",
177
+ ),
178
+ ParameterSpec(
179
+ name="max_payload_bytes",
180
+ kind="string",
181
+ prompt="Taille maximale du payload en octets",
182
+ default="1048576",
183
+ ),
184
+ ParameterSpec(
185
+ name="request_timeout_seconds",
186
+ kind="string",
187
+ prompt="Timeout de chat.postMessage en secondes",
188
+ default="5.0",
189
+ ),
190
+ ),
191
+ dependency_extra="channel",
192
+ entity_scoped=False,
193
+ ),
194
+ ),
195
+ )
196
+
197
+ __all__ = ["CHANNEL_CAPABILITY"]
@@ -6,6 +6,13 @@ from arclith_cli.capability_models import (
6
6
  ParameterSpec,
7
7
  SecretMappingSpec,
8
8
  )
9
+ from arclith_cli.catalogs.repository_facets import (
10
+ DUCKDB_FACETS,
11
+ MARIADB_FACETS,
12
+ MEMORY_FACETS,
13
+ MONGODB_FACETS,
14
+ POSTGRESQL_FACETS,
15
+ )
9
16
 
10
17
  REPOSITORY_CAPABILITY = CapabilitySpec(
11
18
  name="repository",
@@ -18,6 +25,7 @@ REPOSITORY_CAPABILITY = CapabilitySpec(
18
25
  capability="repository",
19
26
  layer="outbound",
20
27
  description="Stockage volatile en mémoire pour dev, tests et smoke locaux.",
28
+ facets=MEMORY_FACETS,
21
29
  ),
22
30
  AdapterSpec(
23
31
  name="mongodb",
@@ -57,6 +65,7 @@ multitenant: {multitenant} # true = uri/db_name résolus par requête via JWT
57
65
  default=False,
58
66
  ),
59
67
  ),
68
+ facets=MONGODB_FACETS,
60
69
  ),
61
70
  AdapterSpec(
62
71
  name="duckdb",
@@ -76,6 +85,7 @@ path: {path}
76
85
  default="data/",
77
86
  ),
78
87
  ),
88
+ facets=DUCKDB_FACETS,
79
89
  ),
80
90
  AdapterSpec(
81
91
  name="mariadb",
@@ -142,6 +152,7 @@ multitenant: false
142
152
  default="",
143
153
  ),
144
154
  ),
155
+ facets=MARIADB_FACETS,
145
156
  ),
146
157
  AdapterSpec(
147
158
  name="postgresql",
@@ -221,6 +232,7 @@ multitenant: {multitenant}
221
232
  default=False,
222
233
  ),
223
234
  ),
235
+ facets=POSTGRESQL_FACETS,
224
236
  ),
225
237
  ),
226
238
  )
@@ -444,3 +456,132 @@ multitenant: {multitenant}
444
456
  ),
445
457
  ),
446
458
  )
459
+
460
+ VECTOR_STORE_CAPABILITY = CapabilitySpec(
461
+ name="vector-store",
462
+ layer="outbound",
463
+ description="Indexation et recherche dense derrière un port provider-neutral.",
464
+ activation_config_key=None,
465
+ adapters=(
466
+ AdapterSpec(
467
+ name="memory",
468
+ capability="vector-store",
469
+ layer="outbound",
470
+ description="Recherche exacte déterministe sans dépendance pour tests et POC.",
471
+ config_path="config/adapters/outbound/vector_store.yaml",
472
+ config_template="""\
473
+ adapter: memory
474
+ collection_name: "{collection_name}"
475
+ vector_size: {vector_size}
476
+ distance: {distance}
477
+ multitenant: {multitenant}
478
+ """,
479
+ parameters=(
480
+ ParameterSpec(
481
+ name="collection_name",
482
+ kind="string",
483
+ prompt="Nom logique de la collection",
484
+ default="default",
485
+ ),
486
+ ParameterSpec(
487
+ name="vector_size",
488
+ kind="string",
489
+ prompt="Dimension obligatoire des vecteurs",
490
+ default="1536",
491
+ ),
492
+ ParameterSpec(
493
+ name="distance",
494
+ kind="string",
495
+ prompt="Métrique de similarité",
496
+ default="cosine",
497
+ choices=("cosine", "dot", "euclid"),
498
+ ),
499
+ ParameterSpec(
500
+ name="multitenant",
501
+ kind="boolean",
502
+ prompt="Réserver la résolution de contexte par tenant",
503
+ default=False,
504
+ ),
505
+ ),
506
+ entity_scoped=False,
507
+ ),
508
+ AdapterSpec(
509
+ name="qdrant",
510
+ capability="vector-store",
511
+ layer="outbound",
512
+ description="Index vectoriel dense Qdrant via le client Python async officiel.",
513
+ config_path="config/adapters/outbound/vector_store.yaml",
514
+ config_template="""\
515
+ adapter: qdrant
516
+ url: "{url}"
517
+ api_key: null
518
+ collection_name: "{collection_name}"
519
+ vector_size: {vector_size}
520
+ distance: {distance}
521
+ prefer_grpc: {prefer_grpc}
522
+ timeout: {timeout}
523
+ create_collection: {create_collection}
524
+ multitenant: {multitenant}
525
+ """,
526
+ secret_mappings=(
527
+ SecretMappingSpec(
528
+ field_path="adapters.vector_store.api_key",
529
+ secret_key="QDRANT_API_KEY",
530
+ ),
531
+ ),
532
+ parameters=(
533
+ ParameterSpec(
534
+ name="url",
535
+ kind="string",
536
+ prompt="Endpoint HTTP Qdrant sans credentials",
537
+ default="http://localhost:6333",
538
+ ),
539
+ ParameterSpec(
540
+ name="collection_name",
541
+ kind="string",
542
+ prompt="Nom de la collection Qdrant",
543
+ default="default",
544
+ ),
545
+ ParameterSpec(
546
+ name="vector_size",
547
+ kind="string",
548
+ prompt="Dimension obligatoire des vecteurs",
549
+ default="1536",
550
+ ),
551
+ ParameterSpec(
552
+ name="distance",
553
+ kind="string",
554
+ prompt="Métrique de similarité",
555
+ default="cosine",
556
+ choices=("cosine", "dot", "euclid"),
557
+ ),
558
+ ParameterSpec(
559
+ name="prefer_grpc",
560
+ kind="boolean",
561
+ prompt="Préférer le transport gRPC",
562
+ default=False,
563
+ ),
564
+ ParameterSpec(
565
+ name="timeout",
566
+ kind="string",
567
+ prompt="Timeout client en secondes",
568
+ default="5.0",
569
+ ),
570
+ ParameterSpec(
571
+ name="create_collection",
572
+ kind="boolean",
573
+ prompt="Créer la collection si elle manque",
574
+ default=True,
575
+ ),
576
+ ParameterSpec(
577
+ name="multitenant",
578
+ kind="boolean",
579
+ prompt="Résoudre url, api_key et collection par tenant",
580
+ default=False,
581
+ ),
582
+ ),
583
+ dependency_extra="qdrant",
584
+ entity_scoped=False,
585
+ ),
586
+ ),
587
+ )