opencode-skills-collection 3.1.10 → 3.1.11
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.
- package/bundled-skills/.antigravity-install-manifest.json +8 -1
- package/bundled-skills/browser-testing-with-devtools/SKILL.md +334 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/sources/sources.md +4 -0
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/drizzle-migration-conflict/SKILL.md +179 -0
- package/bundled-skills/drizzle-migration-conflict/references/ci-policy.md +87 -0
- package/bundled-skills/drizzle-migration-conflict/references/conflict-resolution.md +163 -0
- package/bundled-skills/drizzle-migration-conflict/references/report-template.md +69 -0
- package/bundled-skills/drizzle-migration-conflict/references/sources.md +51 -0
- package/bundled-skills/drizzle-migration-conflict/scripts/check_drizzle_migrations.py +721 -0
- package/bundled-skills/frontend-lighthouse/SKILL.md +348 -0
- package/bundled-skills/pre-release-review/SKILL.md +198 -0
- package/bundled-skills/pre-release-review/references/checklist.md +104 -0
- package/bundled-skills/pre-release-review/references/report-template.md +91 -0
- package/bundled-skills/re-create/SKILL.md +251 -0
- package/bundled-skills/weaviate/SKILL.md +132 -0
- package/bundled-skills/weaviate/references/ask.md +36 -0
- package/bundled-skills/weaviate/references/create_collection.md +152 -0
- package/bundled-skills/weaviate/references/environment_requirements.md +34 -0
- package/bundled-skills/weaviate/references/example_data.md +24 -0
- package/bundled-skills/weaviate/references/explore_collection.md +50 -0
- package/bundled-skills/weaviate/references/fetch_filter.md +88 -0
- package/bundled-skills/weaviate/references/get_collection.md +32 -0
- package/bundled-skills/weaviate/references/hybrid_search.md +47 -0
- package/bundled-skills/weaviate/references/import_data.md +160 -0
- package/bundled-skills/weaviate/references/keyword_search.md +38 -0
- package/bundled-skills/weaviate/references/list_collections.md +31 -0
- package/bundled-skills/weaviate/references/query_search.md +38 -0
- package/bundled-skills/weaviate/references/semantic_search.md +46 -0
- package/bundled-skills/weaviate/scripts/ask.py +106 -0
- package/bundled-skills/weaviate/scripts/create_collection.py +359 -0
- package/bundled-skills/weaviate/scripts/example_data.py +945 -0
- package/bundled-skills/weaviate/scripts/explore_collection.py +295 -0
- package/bundled-skills/weaviate/scripts/fetch_filter.py +261 -0
- package/bundled-skills/weaviate/scripts/get_collection.py +122 -0
- package/bundled-skills/weaviate/scripts/hybrid_search.py +157 -0
- package/bundled-skills/weaviate/scripts/import.py +701 -0
- package/bundled-skills/weaviate/scripts/keyword_search.py +142 -0
- package/bundled-skills/weaviate/scripts/list_collections.py +77 -0
- package/bundled-skills/weaviate/scripts/query_search.py +135 -0
- package/bundled-skills/weaviate/scripts/semantic_search.py +139 -0
- package/bundled-skills/weaviate/scripts/weaviate_conn.py +231 -0
- package/bundled-skills/weaviate-cookbooks/SKILL.md +67 -0
- package/bundled-skills/weaviate-cookbooks/references/advanced_rag.md +274 -0
- package/bundled-skills/weaviate-cookbooks/references/agentic_rag.md +360 -0
- package/bundled-skills/weaviate-cookbooks/references/async_client.md +428 -0
- package/bundled-skills/weaviate-cookbooks/references/basic_agent.md +270 -0
- package/bundled-skills/weaviate-cookbooks/references/basic_rag.md +219 -0
- package/bundled-skills/weaviate-cookbooks/references/data_explorer.md +336 -0
- package/bundled-skills/weaviate-cookbooks/references/environment_requirements.md +78 -0
- package/bundled-skills/weaviate-cookbooks/references/frontend_interface.md +104 -0
- package/bundled-skills/weaviate-cookbooks/references/pdf_multimodal_rag.md +635 -0
- package/bundled-skills/weaviate-cookbooks/references/project_setup.md +75 -0
- package/bundled-skills/weaviate-cookbooks/references/query_agent_chatbot.md +163 -0
- package/package.json +1 -1
- package/skills_index.json +156 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# dependencies = [
|
|
4
|
+
# "weaviate-client==4.19.2",
|
|
5
|
+
# "weaviate-agents==1.2.0",
|
|
6
|
+
# "typer==0.21.0",
|
|
7
|
+
# ]
|
|
8
|
+
# ///
|
|
9
|
+
"""
|
|
10
|
+
Query Weaviate using Query Agent in Ask mode.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
uv run ask.py --query "your question" --collections "Collection1,Collection2" [--json]
|
|
14
|
+
|
|
15
|
+
Environment Variables:
|
|
16
|
+
WEAVIATE_URL: Weaviate Cloud cluster URL
|
|
17
|
+
WEAVIATE_API_KEY: API key for authentication
|
|
18
|
+
+ Any provider API keys (OPENAI_API_KEY, COHERE_API_KEY, etc.) - auto-detected
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
import typer
|
|
25
|
+
import weaviate
|
|
26
|
+
from weaviate.agents.query import QueryAgent
|
|
27
|
+
|
|
28
|
+
# Import shared connection utilities (local to this skill)
|
|
29
|
+
from weaviate_conn import get_client
|
|
30
|
+
|
|
31
|
+
app = typer.Typer()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def parse_collections(collections_str: str) -> list[str]:
|
|
35
|
+
"""Parse comma-separated collection names."""
|
|
36
|
+
collections = [c.strip() for c in collections_str.split(",") if c.strip()]
|
|
37
|
+
if not collections:
|
|
38
|
+
print("Error: At least one collection name required", file=sys.stderr)
|
|
39
|
+
raise typer.Exit(1)
|
|
40
|
+
return collections
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@app.command()
|
|
44
|
+
def main(
|
|
45
|
+
query: str = typer.Option(..., "--query", "-q", help="Natural language question"),
|
|
46
|
+
collections: str = typer.Option(
|
|
47
|
+
..., "--collections", "-c", help="Comma-separated collection names"
|
|
48
|
+
),
|
|
49
|
+
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
|
|
50
|
+
):
|
|
51
|
+
"""Query Weaviate using Query Agent in Ask mode (generates answer with sources)."""
|
|
52
|
+
collection_list = parse_collections(collections)
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
with get_client() as client:
|
|
56
|
+
agent = QueryAgent(client=client, collections=collection_list)
|
|
57
|
+
|
|
58
|
+
print("Generating answer...", file=sys.stderr)
|
|
59
|
+
response = agent.ask(query)
|
|
60
|
+
print("Done.", file=sys.stderr)
|
|
61
|
+
|
|
62
|
+
# Extract data from response
|
|
63
|
+
answer = getattr(response, "final_answer", "") or ""
|
|
64
|
+
sources = []
|
|
65
|
+
if hasattr(response, "sources") and response.sources:
|
|
66
|
+
for src in response.sources:
|
|
67
|
+
sources.append(
|
|
68
|
+
{
|
|
69
|
+
"collection": getattr(src, "collection", None),
|
|
70
|
+
"object_id": getattr(src, "object_id", None),
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
result = {
|
|
75
|
+
"query": query,
|
|
76
|
+
"collections": collection_list,
|
|
77
|
+
"answer": answer,
|
|
78
|
+
"sources": sources,
|
|
79
|
+
"source_count": len(sources),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if json_output:
|
|
83
|
+
print(json.dumps(result, indent=2, default=str))
|
|
84
|
+
else:
|
|
85
|
+
# Markdown output for agent consumption
|
|
86
|
+
print(f"## Answer\n\n{answer}\n")
|
|
87
|
+
|
|
88
|
+
if sources:
|
|
89
|
+
print(f"## Sources ({len(sources)})\n")
|
|
90
|
+
print("| # | Collection | Object ID |")
|
|
91
|
+
print("|---|------------|-----------|")
|
|
92
|
+
for idx, src in enumerate(sources, 1):
|
|
93
|
+
print(
|
|
94
|
+
f"| {idx} | {src.get('collection', 'Unknown')} | `{src.get('object_id', 'N/A')}` |"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
except weaviate.exceptions.WeaviateConnectionError as e:
|
|
98
|
+
print(f"Error: Connection failed - {e}", file=sys.stderr)
|
|
99
|
+
raise typer.Exit(1)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
102
|
+
raise typer.Exit(1)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
app()
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# dependencies = [
|
|
4
|
+
# "weaviate-client==4.19.2",
|
|
5
|
+
# "typer==0.21.0",
|
|
6
|
+
# ]
|
|
7
|
+
# ///
|
|
8
|
+
"""
|
|
9
|
+
Create a Weaviate collection.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
uv run create_collection.py CollectionName --properties '[...]' [options]
|
|
13
|
+
|
|
14
|
+
Environment Variables:
|
|
15
|
+
WEAVIATE_URL: Weaviate Cloud cluster URL
|
|
16
|
+
WEAVIATE_API_KEY: API key for authentication
|
|
17
|
+
+ Any provider API keys (OPENAI_API_KEY, COHERE_API_KEY, etc.) - auto-detected
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
import typer
|
|
24
|
+
import weaviate
|
|
25
|
+
from weaviate.classes.config import (
|
|
26
|
+
Configure,
|
|
27
|
+
DataType,
|
|
28
|
+
Property,
|
|
29
|
+
Tokenization,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Import shared connection utilities (local to this skill)
|
|
33
|
+
from weaviate_conn import get_client
|
|
34
|
+
|
|
35
|
+
app = typer.Typer()
|
|
36
|
+
|
|
37
|
+
# Data type string to enum mapping
|
|
38
|
+
DATA_TYPE_MAP = {
|
|
39
|
+
"text": DataType.TEXT,
|
|
40
|
+
"text[]": DataType.TEXT_ARRAY,
|
|
41
|
+
"boolean": DataType.BOOL,
|
|
42
|
+
"boolean[]": DataType.BOOL_ARRAY,
|
|
43
|
+
"bool": DataType.BOOL,
|
|
44
|
+
"bool[]": DataType.BOOL_ARRAY,
|
|
45
|
+
"int": DataType.INT,
|
|
46
|
+
"int[]": DataType.INT_ARRAY,
|
|
47
|
+
"number": DataType.NUMBER,
|
|
48
|
+
"number[]": DataType.NUMBER_ARRAY,
|
|
49
|
+
"date": DataType.DATE,
|
|
50
|
+
"date[]": DataType.DATE_ARRAY,
|
|
51
|
+
"uuid": DataType.UUID,
|
|
52
|
+
"uuid[]": DataType.UUID_ARRAY,
|
|
53
|
+
"geoCoordinates": DataType.GEO_COORDINATES,
|
|
54
|
+
"phoneNumber": DataType.PHONE_NUMBER,
|
|
55
|
+
"blob": DataType.BLOB,
|
|
56
|
+
"object": DataType.OBJECT,
|
|
57
|
+
"object[]": DataType.OBJECT_ARRAY,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Types that support index_range_filters (enabled by default for better range query performance)
|
|
61
|
+
RANGE_FILTER_TYPES = {"int", "int[]", "number", "number[]", "date", "date[]"}
|
|
62
|
+
|
|
63
|
+
# Tokenization string to enum mapping
|
|
64
|
+
TOKENIZATION_MAP = {
|
|
65
|
+
"word": Tokenization.WORD,
|
|
66
|
+
"lowercase": Tokenization.LOWERCASE,
|
|
67
|
+
"whitespace": Tokenization.WHITESPACE,
|
|
68
|
+
"field": Tokenization.FIELD,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Vectorizer string to config mapping
|
|
72
|
+
VECTORIZER_MAP = {
|
|
73
|
+
"text2vec_weaviate": lambda: Configure.Vectors.text2vec_weaviate(),
|
|
74
|
+
"text2vec_openai": lambda: Configure.Vectors.text2vec_openai(),
|
|
75
|
+
"text2vec_cohere": lambda: Configure.Vectors.text2vec_cohere(),
|
|
76
|
+
"text2vec_huggingface": lambda: Configure.Vectors.text2vec_huggingface(),
|
|
77
|
+
"text2vec_google_gemini": lambda: Configure.Vectors.text2vec_google_gemini(),
|
|
78
|
+
"text2vec_jinaai": lambda: Configure.Vectors.text2vec_jinaai(),
|
|
79
|
+
"text2vec_voyageai": lambda: Configure.Vectors.text2vec_voyageai(),
|
|
80
|
+
"text2vec_model2vec": lambda: Configure.Vectors.text2vec_model2vec(),
|
|
81
|
+
"text2vec_transformers": lambda: Configure.Vectors.text2vec_transformers(),
|
|
82
|
+
"text2vec_ollama": lambda: Configure.Vectors.text2vec_ollama(),
|
|
83
|
+
"multi2vec_clip": lambda: Configure.Vectors.multi2vec_clip(),
|
|
84
|
+
"multi2vec_bind": lambda: Configure.Vectors.multi2vec_bind(),
|
|
85
|
+
"none": lambda: Configure.Vectors.self_provided(),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def parse_property(prop_dict: dict) -> Property:
|
|
90
|
+
"""
|
|
91
|
+
Parse a property definition from a dictionary.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
prop_dict: Dictionary with property definition
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Property instance
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
ValueError: If property definition is invalid
|
|
101
|
+
"""
|
|
102
|
+
if "name" not in prop_dict:
|
|
103
|
+
raise ValueError("Property must have a 'name' field")
|
|
104
|
+
if "data_type" not in prop_dict:
|
|
105
|
+
raise ValueError(
|
|
106
|
+
f"Property '{prop_dict['name']}' must have a 'data_type' field"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
name = prop_dict["name"]
|
|
110
|
+
data_type_str = prop_dict["data_type"].lower()
|
|
111
|
+
|
|
112
|
+
if data_type_str not in DATA_TYPE_MAP:
|
|
113
|
+
raise ValueError(
|
|
114
|
+
f"Invalid data_type '{prop_dict['data_type']}' for property '{name}'. "
|
|
115
|
+
f"Supported types: {', '.join(DATA_TYPE_MAP.keys())}"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
data_type = DATA_TYPE_MAP[data_type_str]
|
|
119
|
+
|
|
120
|
+
# Build property kwargs
|
|
121
|
+
kwargs = {
|
|
122
|
+
"name": name,
|
|
123
|
+
"data_type": data_type,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Add optional fields
|
|
127
|
+
if "description" in prop_dict:
|
|
128
|
+
kwargs["description"] = prop_dict["description"]
|
|
129
|
+
|
|
130
|
+
if "index_filterable" in prop_dict:
|
|
131
|
+
kwargs["index_filterable"] = bool(prop_dict["index_filterable"])
|
|
132
|
+
|
|
133
|
+
if "index_searchable" in prop_dict:
|
|
134
|
+
kwargs["index_searchable"] = bool(prop_dict["index_searchable"])
|
|
135
|
+
|
|
136
|
+
if "index_range_filters" in prop_dict:
|
|
137
|
+
kwargs["index_range_filters"] = bool(prop_dict["index_range_filters"])
|
|
138
|
+
|
|
139
|
+
# Handle tokenization for text types
|
|
140
|
+
if "tokenization" in prop_dict:
|
|
141
|
+
tokenization_str = prop_dict["tokenization"].lower()
|
|
142
|
+
if tokenization_str not in TOKENIZATION_MAP:
|
|
143
|
+
raise ValueError(
|
|
144
|
+
f"Invalid tokenization '{prop_dict['tokenization']}' for property '{name}'. "
|
|
145
|
+
f"Supported: {', '.join(TOKENIZATION_MAP.keys())}"
|
|
146
|
+
)
|
|
147
|
+
kwargs["tokenization"] = TOKENIZATION_MAP[tokenization_str]
|
|
148
|
+
|
|
149
|
+
# Handle nested properties for object types
|
|
150
|
+
if "nested_properties" in prop_dict:
|
|
151
|
+
if data_type not in [DataType.OBJECT, DataType.OBJECT_ARRAY]:
|
|
152
|
+
raise ValueError(
|
|
153
|
+
f"nested_properties can only be used with 'object' or 'object[]' data types "
|
|
154
|
+
f"(property '{name}' has type '{data_type_str}')"
|
|
155
|
+
)
|
|
156
|
+
kwargs["nested_properties"] = [
|
|
157
|
+
parse_property(nested_prop)
|
|
158
|
+
for nested_prop in prop_dict["nested_properties"]
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
return Property(**kwargs)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@app.command()
|
|
165
|
+
def main(
|
|
166
|
+
name: str = typer.Argument(..., help="Collection name (capitalize first letter)"),
|
|
167
|
+
properties: str = typer.Option(
|
|
168
|
+
...,
|
|
169
|
+
"--properties",
|
|
170
|
+
"-p",
|
|
171
|
+
help="JSON array of property definitions. Add a 'description' field to each property — the Query Agent uses these to understand your schema and construct accurate queries.",
|
|
172
|
+
),
|
|
173
|
+
description: str = typer.Option(
|
|
174
|
+
None,
|
|
175
|
+
"--description",
|
|
176
|
+
"-d",
|
|
177
|
+
help="Collection description. Weaviate agents read this to understand what the collection contains and decide which collection to query.",
|
|
178
|
+
),
|
|
179
|
+
vectorizer: str = typer.Option(
|
|
180
|
+
"text2vec_weaviate",
|
|
181
|
+
"--vectorizer",
|
|
182
|
+
"-v",
|
|
183
|
+
help=f"Vectorizer to use. Options: {', '.join(VECTORIZER_MAP.keys())}",
|
|
184
|
+
),
|
|
185
|
+
replication_factor: int = typer.Option(
|
|
186
|
+
None, "--replication-factor", "-r", help="Replication factor (default: 1)"
|
|
187
|
+
),
|
|
188
|
+
multi_tenancy: bool = typer.Option(
|
|
189
|
+
False, "--multi-tenancy", "-m", help="Enable multi-tenancy for data isolation"
|
|
190
|
+
),
|
|
191
|
+
auto_tenant_creation: bool = typer.Option(
|
|
192
|
+
False,
|
|
193
|
+
"--auto-tenant-creation",
|
|
194
|
+
"-a",
|
|
195
|
+
help="Auto-create tenants on insert (requires --multi-tenancy)",
|
|
196
|
+
),
|
|
197
|
+
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
|
|
198
|
+
):
|
|
199
|
+
"""Create a new Weaviate collection with specified properties."""
|
|
200
|
+
try:
|
|
201
|
+
# Validate multi-tenancy options
|
|
202
|
+
if auto_tenant_creation and not multi_tenancy:
|
|
203
|
+
print(
|
|
204
|
+
"Error: --auto-tenant-creation requires --multi-tenancy to be enabled",
|
|
205
|
+
file=sys.stderr,
|
|
206
|
+
)
|
|
207
|
+
raise typer.Exit(1)
|
|
208
|
+
|
|
209
|
+
# Validate collection name (should start with uppercase)
|
|
210
|
+
if not name[0].isupper():
|
|
211
|
+
print(
|
|
212
|
+
f"Warning: Collection name '{name}' should start with an uppercase letter "
|
|
213
|
+
f"(GraphQL naming convention).",
|
|
214
|
+
file=sys.stderr,
|
|
215
|
+
)
|
|
216
|
+
name = name.capitalize()
|
|
217
|
+
print(f"Using '{name}' instead.", file=sys.stderr)
|
|
218
|
+
|
|
219
|
+
# Parse properties JSON
|
|
220
|
+
try:
|
|
221
|
+
properties_list = json.loads(properties)
|
|
222
|
+
if not isinstance(properties_list, list):
|
|
223
|
+
raise ValueError("Properties must be a JSON array")
|
|
224
|
+
if len(properties_list) == 0:
|
|
225
|
+
raise ValueError("Properties array cannot be empty")
|
|
226
|
+
except json.JSONDecodeError as e:
|
|
227
|
+
print(f"Error: Invalid JSON in properties: {e}", file=sys.stderr)
|
|
228
|
+
raise typer.Exit(1)
|
|
229
|
+
|
|
230
|
+
# Parse each property
|
|
231
|
+
try:
|
|
232
|
+
parsed_properties = [parse_property(prop) for prop in properties_list]
|
|
233
|
+
except ValueError as e:
|
|
234
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
235
|
+
raise typer.Exit(1)
|
|
236
|
+
|
|
237
|
+
# Prepare collection config
|
|
238
|
+
collection_config = {
|
|
239
|
+
"name": name,
|
|
240
|
+
"properties": parsed_properties,
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if description:
|
|
244
|
+
collection_config["description"] = description
|
|
245
|
+
|
|
246
|
+
# Add vectorizer if specified
|
|
247
|
+
if vectorizer:
|
|
248
|
+
vectorizer_lower = vectorizer.lower()
|
|
249
|
+
if vectorizer_lower not in VECTORIZER_MAP:
|
|
250
|
+
print(
|
|
251
|
+
f"Error: Invalid vectorizer '{vectorizer}'. "
|
|
252
|
+
f"Supported: {', '.join(VECTORIZER_MAP.keys())}",
|
|
253
|
+
file=sys.stderr,
|
|
254
|
+
)
|
|
255
|
+
raise typer.Exit(1)
|
|
256
|
+
collection_config["vector_config"] = VECTORIZER_MAP[vectorizer_lower]()
|
|
257
|
+
|
|
258
|
+
# Add replication config if specified
|
|
259
|
+
if replication_factor is not None:
|
|
260
|
+
if replication_factor < 1:
|
|
261
|
+
print("Error: Replication factor must be at least 1", file=sys.stderr)
|
|
262
|
+
raise typer.Exit(1)
|
|
263
|
+
collection_config["replication_config"] = Configure.replication(
|
|
264
|
+
factor=replication_factor
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Add multi-tenancy config if specified
|
|
268
|
+
if multi_tenancy:
|
|
269
|
+
collection_config["multi_tenancy_config"] = Configure.multi_tenancy(
|
|
270
|
+
enabled=True, auto_tenant_creation=auto_tenant_creation
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
with get_client() as client:
|
|
274
|
+
# Check if collection already exists
|
|
275
|
+
if client.collections.exists(name):
|
|
276
|
+
print(
|
|
277
|
+
f"Error: Collection '{name}' already exists. "
|
|
278
|
+
f"Delete it first or use a different name.",
|
|
279
|
+
file=sys.stderr,
|
|
280
|
+
)
|
|
281
|
+
raise typer.Exit(1)
|
|
282
|
+
|
|
283
|
+
print(f"Creating collection '{name}'...", file=sys.stderr)
|
|
284
|
+
client.collections.create(**collection_config)
|
|
285
|
+
|
|
286
|
+
# Verify creation by fetching the config
|
|
287
|
+
collection = client.collections.get(name)
|
|
288
|
+
config = collection.config.get()
|
|
289
|
+
|
|
290
|
+
result = {
|
|
291
|
+
"name": name,
|
|
292
|
+
"description": config.description,
|
|
293
|
+
"properties": [
|
|
294
|
+
{
|
|
295
|
+
"name": p.name,
|
|
296
|
+
"data_type": str(p.data_type),
|
|
297
|
+
"description": getattr(p, "description", None),
|
|
298
|
+
}
|
|
299
|
+
for p in config.properties
|
|
300
|
+
],
|
|
301
|
+
"multi_tenancy": {
|
|
302
|
+
"enabled": (
|
|
303
|
+
config.multi_tenancy_config.enabled
|
|
304
|
+
if config.multi_tenancy_config
|
|
305
|
+
else False
|
|
306
|
+
),
|
|
307
|
+
"auto_tenant_creation": (
|
|
308
|
+
config.multi_tenancy_config.auto_tenant_creation
|
|
309
|
+
if config.multi_tenancy_config
|
|
310
|
+
else False
|
|
311
|
+
),
|
|
312
|
+
},
|
|
313
|
+
"status": "created",
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if json_output:
|
|
317
|
+
print(json.dumps(result, indent=2, default=str))
|
|
318
|
+
else:
|
|
319
|
+
print(f"\n✓ Collection '{name}' created successfully!\n")
|
|
320
|
+
if not result["description"]:
|
|
321
|
+
print(
|
|
322
|
+
"Tip: No collection description provided. "
|
|
323
|
+
"Weaviate agents read the collection description to understand what data it contains and decide which collection to query.",
|
|
324
|
+
file=sys.stderr,
|
|
325
|
+
)
|
|
326
|
+
props_without_desc = [
|
|
327
|
+
p["name"] for p in result["properties"] if not p.get("description")
|
|
328
|
+
]
|
|
329
|
+
if props_without_desc:
|
|
330
|
+
print(
|
|
331
|
+
f"Tip: {len(props_without_desc)} propert{'y has' if len(props_without_desc) == 1 else 'ies have'} no description. "
|
|
332
|
+
f"Adding descriptions helps the Query Agent understand your schema and construct accurate queries.",
|
|
333
|
+
file=sys.stderr,
|
|
334
|
+
)
|
|
335
|
+
print(f"**Description:** {config.description or 'N/A'}")
|
|
336
|
+
|
|
337
|
+
# Display multi-tenancy status
|
|
338
|
+
if result["multi_tenancy"]["enabled"]:
|
|
339
|
+
print(f"**Multi-Tenancy:** Enabled")
|
|
340
|
+
if result["multi_tenancy"]["auto_tenant_creation"]:
|
|
341
|
+
print(f"**Auto-Tenant Creation:** Enabled")
|
|
342
|
+
|
|
343
|
+
print(f"\n### Properties ({len(config.properties)})\n")
|
|
344
|
+
print("| Name | Data Type | Description |")
|
|
345
|
+
print("|------|-----------|-------------|")
|
|
346
|
+
for prop in result["properties"]:
|
|
347
|
+
desc = prop.get("description") or "-"
|
|
348
|
+
print(f"| {prop['name']} | {prop['data_type']} | {desc} |")
|
|
349
|
+
|
|
350
|
+
except weaviate.exceptions.WeaviateConnectionError as e:
|
|
351
|
+
print(f"Error: Connection failed - {e}", file=sys.stderr)
|
|
352
|
+
raise typer.Exit(1)
|
|
353
|
+
except Exception as e:
|
|
354
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
355
|
+
raise typer.Exit(1)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
if __name__ == "__main__":
|
|
359
|
+
app()
|