llama-stack 0.4.3__py3-none-any.whl → 0.5.0rc1__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.
- llama_stack/cli/stack/_list_deps.py +11 -7
- llama_stack/cli/stack/run.py +3 -25
- llama_stack/core/access_control/datatypes.py +78 -0
- llama_stack/core/configure.py +2 -2
- {llama_stack_api/internal → llama_stack/core/connectors}/__init__.py +2 -2
- llama_stack/core/connectors/connectors.py +162 -0
- llama_stack/core/conversations/conversations.py +61 -58
- llama_stack/core/datatypes.py +54 -8
- llama_stack/core/library_client.py +60 -13
- llama_stack/core/prompts/prompts.py +43 -42
- llama_stack/core/routers/datasets.py +20 -17
- llama_stack/core/routers/eval_scoring.py +143 -53
- llama_stack/core/routers/inference.py +20 -9
- llama_stack/core/routers/safety.py +30 -42
- llama_stack/core/routers/vector_io.py +15 -7
- llama_stack/core/routing_tables/models.py +42 -3
- llama_stack/core/routing_tables/scoring_functions.py +19 -19
- llama_stack/core/routing_tables/shields.py +20 -17
- llama_stack/core/routing_tables/vector_stores.py +8 -5
- llama_stack/core/server/auth.py +192 -17
- llama_stack/core/server/fastapi_router_registry.py +40 -5
- llama_stack/core/server/server.py +24 -5
- llama_stack/core/stack.py +54 -10
- llama_stack/core/storage/datatypes.py +9 -0
- llama_stack/core/store/registry.py +1 -1
- llama_stack/core/utils/exec.py +2 -2
- llama_stack/core/utils/type_inspection.py +16 -2
- llama_stack/distributions/dell/config.yaml +4 -1
- llama_stack/distributions/dell/doc_template.md +209 -0
- llama_stack/distributions/dell/run-with-safety.yaml +4 -1
- llama_stack/distributions/nvidia/config.yaml +4 -1
- llama_stack/distributions/nvidia/doc_template.md +170 -0
- llama_stack/distributions/nvidia/run-with-safety.yaml +4 -1
- llama_stack/distributions/oci/config.yaml +4 -1
- llama_stack/distributions/oci/doc_template.md +140 -0
- llama_stack/distributions/open-benchmark/config.yaml +9 -1
- llama_stack/distributions/postgres-demo/config.yaml +1 -1
- llama_stack/distributions/starter/build.yaml +62 -0
- llama_stack/distributions/starter/config.yaml +22 -3
- llama_stack/distributions/starter/run-with-postgres-store.yaml +22 -3
- llama_stack/distributions/starter/starter.py +13 -1
- llama_stack/distributions/starter-gpu/build.yaml +62 -0
- llama_stack/distributions/starter-gpu/config.yaml +22 -3
- llama_stack/distributions/starter-gpu/run-with-postgres-store.yaml +22 -3
- llama_stack/distributions/template.py +10 -2
- llama_stack/distributions/watsonx/config.yaml +4 -1
- llama_stack/log.py +1 -0
- llama_stack/models/llama/resources/dog.jpg +0 -0
- llama_stack/models/llama/resources/pasta.jpeg +0 -0
- llama_stack/models/llama/resources/small_dog.jpg +0 -0
- llama_stack/providers/inline/agents/meta_reference/__init__.py +1 -0
- llama_stack/providers/inline/agents/meta_reference/agents.py +57 -61
- llama_stack/providers/inline/agents/meta_reference/responses/openai_responses.py +183 -60
- llama_stack/providers/inline/agents/meta_reference/responses/streaming.py +94 -22
- llama_stack/providers/inline/agents/meta_reference/responses/types.py +2 -1
- llama_stack/providers/inline/agents/meta_reference/responses/utils.py +4 -1
- llama_stack/providers/inline/agents/meta_reference/safety.py +2 -2
- llama_stack/providers/inline/batches/reference/batches.py +2 -1
- llama_stack/providers/inline/eval/meta_reference/eval.py +40 -32
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl/LocalInference.h +9 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl/LocalInference.swift +189 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl/Parsing.swift +238 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl/PromptTemplate.swift +12 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl/SystemPrompts.swift +89 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl.xcodeproj/project.pbxproj +550 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- llama_stack/providers/inline/ios/inference/LocalInferenceImpl.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- llama_stack/providers/inline/post_training/huggingface/post_training.py +33 -38
- llama_stack/providers/inline/post_training/huggingface/utils.py +2 -5
- llama_stack/providers/inline/post_training/torchtune/post_training.py +28 -33
- llama_stack/providers/inline/post_training/torchtune/recipes/lora_finetuning_single_device.py +2 -4
- llama_stack/providers/inline/safety/code_scanner/code_scanner.py +12 -15
- llama_stack/providers/inline/safety/llama_guard/llama_guard.py +15 -18
- llama_stack/providers/inline/safety/prompt_guard/prompt_guard.py +11 -17
- llama_stack/providers/inline/scoring/basic/scoring.py +13 -17
- llama_stack/providers/inline/scoring/braintrust/braintrust.py +15 -15
- llama_stack/providers/inline/scoring/llm_as_judge/scoring.py +13 -17
- llama_stack/providers/inline/vector_io/sqlite_vec/sqlite_vec.py +1 -1
- llama_stack/providers/registry/agents.py +1 -0
- llama_stack/providers/registry/inference.py +1 -9
- llama_stack/providers/registry/vector_io.py +136 -16
- llama_stack/providers/remote/datasetio/nvidia/README.md +74 -0
- llama_stack/providers/remote/eval/nvidia/README.md +134 -0
- llama_stack/providers/remote/eval/nvidia/eval.py +22 -21
- llama_stack/providers/remote/files/s3/README.md +266 -0
- llama_stack/providers/remote/files/s3/config.py +5 -3
- llama_stack/providers/remote/files/s3/files.py +2 -2
- llama_stack/providers/remote/inference/gemini/gemini.py +4 -0
- llama_stack/providers/remote/inference/nvidia/NVIDIA.md +203 -0
- llama_stack/providers/remote/inference/openai/openai.py +2 -0
- llama_stack/providers/remote/inference/together/together.py +4 -0
- llama_stack/providers/remote/inference/vertexai/config.py +3 -3
- llama_stack/providers/remote/inference/vertexai/vertexai.py +5 -2
- llama_stack/providers/remote/inference/vllm/config.py +37 -18
- llama_stack/providers/remote/inference/vllm/vllm.py +0 -3
- llama_stack/providers/remote/inference/watsonx/watsonx.py +4 -0
- llama_stack/providers/remote/post_training/nvidia/README.md +151 -0
- llama_stack/providers/remote/post_training/nvidia/post_training.py +31 -33
- llama_stack/providers/remote/safety/bedrock/bedrock.py +10 -27
- llama_stack/providers/remote/safety/nvidia/README.md +78 -0
- llama_stack/providers/remote/safety/nvidia/nvidia.py +9 -25
- llama_stack/providers/remote/safety/sambanova/sambanova.py +13 -11
- llama_stack/providers/remote/vector_io/elasticsearch/__init__.py +17 -0
- llama_stack/providers/remote/vector_io/elasticsearch/config.py +32 -0
- llama_stack/providers/remote/vector_io/elasticsearch/elasticsearch.py +463 -0
- llama_stack/providers/remote/vector_io/oci/__init__.py +22 -0
- llama_stack/providers/remote/vector_io/oci/config.py +41 -0
- llama_stack/providers/remote/vector_io/oci/oci26ai.py +595 -0
- llama_stack/providers/remote/vector_io/pgvector/config.py +69 -2
- llama_stack/providers/remote/vector_io/pgvector/pgvector.py +255 -6
- llama_stack/providers/remote/vector_io/qdrant/qdrant.py +62 -38
- llama_stack/providers/utils/bedrock/client.py +3 -3
- llama_stack/providers/utils/bedrock/config.py +7 -7
- llama_stack/providers/utils/inference/embedding_mixin.py +4 -0
- llama_stack/providers/utils/inference/http_client.py +239 -0
- llama_stack/providers/utils/inference/litellm_openai_mixin.py +5 -0
- llama_stack/providers/utils/inference/model_registry.py +148 -2
- llama_stack/providers/utils/inference/openai_compat.py +2 -1
- llama_stack/providers/utils/inference/openai_mixin.py +41 -2
- llama_stack/providers/utils/memory/openai_vector_store_mixin.py +92 -5
- llama_stack/providers/utils/memory/vector_store.py +46 -19
- llama_stack/providers/utils/responses/responses_store.py +40 -6
- llama_stack/providers/utils/safety.py +114 -0
- llama_stack/providers/utils/tools/mcp.py +44 -3
- llama_stack/testing/api_recorder.py +9 -3
- {llama_stack-0.4.3.dist-info → llama_stack-0.5.0rc1.dist-info}/METADATA +14 -2
- {llama_stack-0.4.3.dist-info → llama_stack-0.5.0rc1.dist-info}/RECORD +131 -275
- llama_stack-0.5.0rc1.dist-info/top_level.txt +1 -0
- llama_stack/distributions/meta-reference-gpu/__init__.py +0 -7
- llama_stack/distributions/meta-reference-gpu/config.yaml +0 -140
- llama_stack/distributions/meta-reference-gpu/meta_reference.py +0 -163
- llama_stack/distributions/meta-reference-gpu/run-with-safety.yaml +0 -155
- llama_stack/models/llama/hadamard_utils.py +0 -88
- llama_stack/models/llama/llama3/args.py +0 -74
- llama_stack/models/llama/llama3/generation.py +0 -378
- llama_stack/models/llama/llama3/model.py +0 -304
- llama_stack/models/llama/llama3/multimodal/__init__.py +0 -12
- llama_stack/models/llama/llama3/multimodal/encoder_utils.py +0 -180
- llama_stack/models/llama/llama3/multimodal/image_transform.py +0 -409
- llama_stack/models/llama/llama3/multimodal/model.py +0 -1430
- llama_stack/models/llama/llama3/multimodal/utils.py +0 -26
- llama_stack/models/llama/llama3/quantization/__init__.py +0 -5
- llama_stack/models/llama/llama3/quantization/loader.py +0 -316
- llama_stack/models/llama/llama3_1/__init__.py +0 -12
- llama_stack/models/llama/llama3_1/prompt_format.md +0 -358
- llama_stack/models/llama/llama3_1/prompts.py +0 -258
- llama_stack/models/llama/llama3_2/__init__.py +0 -5
- llama_stack/models/llama/llama3_2/prompts_text.py +0 -229
- llama_stack/models/llama/llama3_2/prompts_vision.py +0 -126
- llama_stack/models/llama/llama3_2/text_prompt_format.md +0 -286
- llama_stack/models/llama/llama3_2/vision_prompt_format.md +0 -141
- llama_stack/models/llama/llama3_3/__init__.py +0 -5
- llama_stack/models/llama/llama3_3/prompts.py +0 -259
- llama_stack/models/llama/llama4/args.py +0 -107
- llama_stack/models/llama/llama4/ffn.py +0 -58
- llama_stack/models/llama/llama4/moe.py +0 -214
- llama_stack/models/llama/llama4/preprocess.py +0 -435
- llama_stack/models/llama/llama4/quantization/__init__.py +0 -5
- llama_stack/models/llama/llama4/quantization/loader.py +0 -226
- llama_stack/models/llama/llama4/vision/__init__.py +0 -5
- llama_stack/models/llama/llama4/vision/embedding.py +0 -210
- llama_stack/models/llama/llama4/vision/encoder.py +0 -412
- llama_stack/models/llama/quantize_impls.py +0 -316
- llama_stack/providers/inline/inference/meta_reference/__init__.py +0 -20
- llama_stack/providers/inline/inference/meta_reference/common.py +0 -24
- llama_stack/providers/inline/inference/meta_reference/config.py +0 -68
- llama_stack/providers/inline/inference/meta_reference/generators.py +0 -201
- llama_stack/providers/inline/inference/meta_reference/inference.py +0 -542
- llama_stack/providers/inline/inference/meta_reference/model_parallel.py +0 -77
- llama_stack/providers/inline/inference/meta_reference/parallel_utils.py +0 -353
- llama_stack-0.4.3.dist-info/top_level.txt +0 -2
- llama_stack_api/__init__.py +0 -945
- llama_stack_api/admin/__init__.py +0 -45
- llama_stack_api/admin/api.py +0 -72
- llama_stack_api/admin/fastapi_routes.py +0 -117
- llama_stack_api/admin/models.py +0 -113
- llama_stack_api/agents.py +0 -173
- llama_stack_api/batches/__init__.py +0 -40
- llama_stack_api/batches/api.py +0 -53
- llama_stack_api/batches/fastapi_routes.py +0 -113
- llama_stack_api/batches/models.py +0 -78
- llama_stack_api/benchmarks/__init__.py +0 -43
- llama_stack_api/benchmarks/api.py +0 -39
- llama_stack_api/benchmarks/fastapi_routes.py +0 -109
- llama_stack_api/benchmarks/models.py +0 -109
- llama_stack_api/common/__init__.py +0 -5
- llama_stack_api/common/content_types.py +0 -101
- llama_stack_api/common/errors.py +0 -95
- llama_stack_api/common/job_types.py +0 -38
- llama_stack_api/common/responses.py +0 -77
- llama_stack_api/common/training_types.py +0 -47
- llama_stack_api/common/type_system.py +0 -146
- llama_stack_api/connectors.py +0 -146
- llama_stack_api/conversations.py +0 -270
- llama_stack_api/datasetio.py +0 -55
- llama_stack_api/datasets/__init__.py +0 -61
- llama_stack_api/datasets/api.py +0 -35
- llama_stack_api/datasets/fastapi_routes.py +0 -104
- llama_stack_api/datasets/models.py +0 -152
- llama_stack_api/datatypes.py +0 -373
- llama_stack_api/eval.py +0 -137
- llama_stack_api/file_processors/__init__.py +0 -27
- llama_stack_api/file_processors/api.py +0 -64
- llama_stack_api/file_processors/fastapi_routes.py +0 -78
- llama_stack_api/file_processors/models.py +0 -42
- llama_stack_api/files/__init__.py +0 -35
- llama_stack_api/files/api.py +0 -51
- llama_stack_api/files/fastapi_routes.py +0 -124
- llama_stack_api/files/models.py +0 -107
- llama_stack_api/inference.py +0 -1169
- llama_stack_api/inspect_api/__init__.py +0 -37
- llama_stack_api/inspect_api/api.py +0 -25
- llama_stack_api/inspect_api/fastapi_routes.py +0 -76
- llama_stack_api/inspect_api/models.py +0 -28
- llama_stack_api/internal/kvstore.py +0 -28
- llama_stack_api/internal/sqlstore.py +0 -81
- llama_stack_api/llama_stack_api/__init__.py +0 -945
- llama_stack_api/llama_stack_api/admin/__init__.py +0 -45
- llama_stack_api/llama_stack_api/admin/api.py +0 -72
- llama_stack_api/llama_stack_api/admin/fastapi_routes.py +0 -117
- llama_stack_api/llama_stack_api/admin/models.py +0 -113
- llama_stack_api/llama_stack_api/agents.py +0 -173
- llama_stack_api/llama_stack_api/batches/__init__.py +0 -40
- llama_stack_api/llama_stack_api/batches/api.py +0 -53
- llama_stack_api/llama_stack_api/batches/fastapi_routes.py +0 -113
- llama_stack_api/llama_stack_api/batches/models.py +0 -78
- llama_stack_api/llama_stack_api/benchmarks/__init__.py +0 -43
- llama_stack_api/llama_stack_api/benchmarks/api.py +0 -39
- llama_stack_api/llama_stack_api/benchmarks/fastapi_routes.py +0 -109
- llama_stack_api/llama_stack_api/benchmarks/models.py +0 -109
- llama_stack_api/llama_stack_api/common/__init__.py +0 -5
- llama_stack_api/llama_stack_api/common/content_types.py +0 -101
- llama_stack_api/llama_stack_api/common/errors.py +0 -95
- llama_stack_api/llama_stack_api/common/job_types.py +0 -38
- llama_stack_api/llama_stack_api/common/responses.py +0 -77
- llama_stack_api/llama_stack_api/common/training_types.py +0 -47
- llama_stack_api/llama_stack_api/common/type_system.py +0 -146
- llama_stack_api/llama_stack_api/connectors.py +0 -146
- llama_stack_api/llama_stack_api/conversations.py +0 -270
- llama_stack_api/llama_stack_api/datasetio.py +0 -55
- llama_stack_api/llama_stack_api/datasets/__init__.py +0 -61
- llama_stack_api/llama_stack_api/datasets/api.py +0 -35
- llama_stack_api/llama_stack_api/datasets/fastapi_routes.py +0 -104
- llama_stack_api/llama_stack_api/datasets/models.py +0 -152
- llama_stack_api/llama_stack_api/datatypes.py +0 -373
- llama_stack_api/llama_stack_api/eval.py +0 -137
- llama_stack_api/llama_stack_api/file_processors/__init__.py +0 -27
- llama_stack_api/llama_stack_api/file_processors/api.py +0 -64
- llama_stack_api/llama_stack_api/file_processors/fastapi_routes.py +0 -78
- llama_stack_api/llama_stack_api/file_processors/models.py +0 -42
- llama_stack_api/llama_stack_api/files/__init__.py +0 -35
- llama_stack_api/llama_stack_api/files/api.py +0 -51
- llama_stack_api/llama_stack_api/files/fastapi_routes.py +0 -124
- llama_stack_api/llama_stack_api/files/models.py +0 -107
- llama_stack_api/llama_stack_api/inference.py +0 -1169
- llama_stack_api/llama_stack_api/inspect_api/__init__.py +0 -37
- llama_stack_api/llama_stack_api/inspect_api/api.py +0 -25
- llama_stack_api/llama_stack_api/inspect_api/fastapi_routes.py +0 -76
- llama_stack_api/llama_stack_api/inspect_api/models.py +0 -28
- llama_stack_api/llama_stack_api/internal/__init__.py +0 -9
- llama_stack_api/llama_stack_api/internal/kvstore.py +0 -28
- llama_stack_api/llama_stack_api/internal/sqlstore.py +0 -81
- llama_stack_api/llama_stack_api/models.py +0 -171
- llama_stack_api/llama_stack_api/openai_responses.py +0 -1468
- llama_stack_api/llama_stack_api/post_training.py +0 -370
- llama_stack_api/llama_stack_api/prompts.py +0 -203
- llama_stack_api/llama_stack_api/providers/__init__.py +0 -33
- llama_stack_api/llama_stack_api/providers/api.py +0 -16
- llama_stack_api/llama_stack_api/providers/fastapi_routes.py +0 -57
- llama_stack_api/llama_stack_api/providers/models.py +0 -24
- llama_stack_api/llama_stack_api/py.typed +0 -0
- llama_stack_api/llama_stack_api/rag_tool.py +0 -168
- llama_stack_api/llama_stack_api/resource.py +0 -37
- llama_stack_api/llama_stack_api/router_utils.py +0 -160
- llama_stack_api/llama_stack_api/safety.py +0 -132
- llama_stack_api/llama_stack_api/schema_utils.py +0 -208
- llama_stack_api/llama_stack_api/scoring.py +0 -93
- llama_stack_api/llama_stack_api/scoring_functions.py +0 -211
- llama_stack_api/llama_stack_api/shields.py +0 -93
- llama_stack_api/llama_stack_api/tools.py +0 -226
- llama_stack_api/llama_stack_api/vector_io.py +0 -941
- llama_stack_api/llama_stack_api/vector_stores.py +0 -53
- llama_stack_api/llama_stack_api/version.py +0 -9
- llama_stack_api/models.py +0 -171
- llama_stack_api/openai_responses.py +0 -1468
- llama_stack_api/post_training.py +0 -370
- llama_stack_api/prompts.py +0 -203
- llama_stack_api/providers/__init__.py +0 -33
- llama_stack_api/providers/api.py +0 -16
- llama_stack_api/providers/fastapi_routes.py +0 -57
- llama_stack_api/providers/models.py +0 -24
- llama_stack_api/py.typed +0 -0
- llama_stack_api/rag_tool.py +0 -168
- llama_stack_api/resource.py +0 -37
- llama_stack_api/router_utils.py +0 -160
- llama_stack_api/safety.py +0 -132
- llama_stack_api/schema_utils.py +0 -208
- llama_stack_api/scoring.py +0 -93
- llama_stack_api/scoring_functions.py +0 -211
- llama_stack_api/shields.py +0 -93
- llama_stack_api/tools.py +0 -226
- llama_stack_api/vector_io.py +0 -941
- llama_stack_api/vector_stores.py +0 -53
- llama_stack_api/version.py +0 -9
- {llama_stack-0.4.3.dist-info → llama_stack-0.5.0rc1.dist-info}/WHEEL +0 -0
- {llama_stack-0.4.3.dist-info → llama_stack-0.5.0rc1.dist-info}/entry_points.txt +0 -0
- {llama_stack-0.4.3.dist-info → llama_stack-0.5.0rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -47,16 +47,20 @@ def format_output_deps_only(
|
|
|
47
47
|
uv_str = ""
|
|
48
48
|
if uv:
|
|
49
49
|
uv_str = "uv pip install "
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
# Only quote when emitting a shell command. In deps-only mode, keep raw
|
|
51
|
+
# specs so they can be safely consumed via command substitution.
|
|
52
|
+
formatted_normal_deps = [quote_if_needed(dep) for dep in normal_deps]
|
|
53
|
+
else:
|
|
54
|
+
formatted_normal_deps = normal_deps
|
|
55
|
+
lines.append(f"{uv_str}{' '.join(formatted_normal_deps)}")
|
|
54
56
|
|
|
55
57
|
for special_dep in special_deps:
|
|
56
|
-
|
|
58
|
+
formatted = quote_special_dep(special_dep) if uv else special_dep
|
|
59
|
+
lines.append(f"{uv_str}{formatted}")
|
|
57
60
|
|
|
58
61
|
for external_dep in external_deps:
|
|
59
|
-
|
|
62
|
+
formatted = quote_special_dep(external_dep) if uv else external_dep
|
|
63
|
+
lines.append(f"{uv_str}{formatted}")
|
|
60
64
|
|
|
61
65
|
return "\n".join(lines)
|
|
62
66
|
|
|
@@ -119,7 +123,7 @@ def run_stack_list_deps_command(args: argparse.Namespace) -> None:
|
|
|
119
123
|
file=sys.stderr,
|
|
120
124
|
)
|
|
121
125
|
sys.exit(1)
|
|
122
|
-
config = StackConfig(providers=provider_list,
|
|
126
|
+
config = StackConfig(providers=provider_list, distro_name="providers-run")
|
|
123
127
|
|
|
124
128
|
normal_deps, special_deps, external_provider_dependencies = get_provider_dependencies(config)
|
|
125
129
|
normal_deps += SERVER_DEPENDENCIES
|
llama_stack/cli/stack/run.py
CHANGED
|
@@ -15,11 +15,10 @@ import uvicorn
|
|
|
15
15
|
import yaml
|
|
16
16
|
from termcolor import cprint
|
|
17
17
|
|
|
18
|
-
from llama_stack.cli.stack.utils import ImageType
|
|
19
18
|
from llama_stack.cli.subcommand import Subcommand
|
|
20
19
|
from llama_stack.core.datatypes import Api, Provider, StackConfig
|
|
21
20
|
from llama_stack.core.distribution import get_provider_registry
|
|
22
|
-
from llama_stack.core.stack import
|
|
21
|
+
from llama_stack.core.stack import cast_distro_name_to_string, replace_env_vars
|
|
23
22
|
from llama_stack.core.storage.datatypes import (
|
|
24
23
|
InferenceStoreReference,
|
|
25
24
|
KVStoreReference,
|
|
@@ -65,18 +64,6 @@ class StackRun(Subcommand):
|
|
|
65
64
|
help="Port to run the server on. It can also be passed via the env var LLAMA_STACK_PORT.",
|
|
66
65
|
default=int(os.getenv("LLAMA_STACK_PORT", 8321)),
|
|
67
66
|
)
|
|
68
|
-
self.parser.add_argument(
|
|
69
|
-
"--image-name",
|
|
70
|
-
type=str,
|
|
71
|
-
default=None,
|
|
72
|
-
help="[DEPRECATED] This flag is no longer supported. Please activate your virtual environment before running.",
|
|
73
|
-
)
|
|
74
|
-
self.parser.add_argument(
|
|
75
|
-
"--image-type",
|
|
76
|
-
type=str,
|
|
77
|
-
help="[DEPRECATED] This flag is no longer supported. Please activate your virtual environment before running.",
|
|
78
|
-
choices=[e.value for e in ImageType if e.value != ImageType.CONTAINER.value],
|
|
79
|
-
)
|
|
80
67
|
self.parser.add_argument(
|
|
81
68
|
"--enable-ui",
|
|
82
69
|
action="store_true",
|
|
@@ -94,15 +81,6 @@ class StackRun(Subcommand):
|
|
|
94
81
|
|
|
95
82
|
from llama_stack.core.configure import parse_and_maybe_upgrade_config
|
|
96
83
|
|
|
97
|
-
if args.image_type or args.image_name:
|
|
98
|
-
self.parser.error(
|
|
99
|
-
"The --image-type and --image-name flags are no longer supported.\n\n"
|
|
100
|
-
"Please activate your virtual environment manually before running `llama stack run`.\n\n"
|
|
101
|
-
"For example:\n"
|
|
102
|
-
" source /path/to/venv/bin/activate\n"
|
|
103
|
-
" llama stack run <config>\n"
|
|
104
|
-
)
|
|
105
|
-
|
|
106
84
|
if args.enable_ui:
|
|
107
85
|
self._start_ui_development_server(args.port)
|
|
108
86
|
|
|
@@ -194,7 +172,7 @@ class StackRun(Subcommand):
|
|
|
194
172
|
logger_config = LoggingConfig(**cfg)
|
|
195
173
|
else:
|
|
196
174
|
logger_config = None
|
|
197
|
-
config = StackConfig(**
|
|
175
|
+
config = StackConfig(**cast_distro_name_to_string(replace_env_vars(config_contents)))
|
|
198
176
|
|
|
199
177
|
port = args.port or config.server.port
|
|
200
178
|
host = config.server.host or ["::", "0.0.0.0"]
|
|
@@ -322,7 +300,7 @@ class StackRun(Subcommand):
|
|
|
322
300
|
)
|
|
323
301
|
|
|
324
302
|
return StackConfig(
|
|
325
|
-
|
|
303
|
+
distro_name="providers-run",
|
|
326
304
|
apis=apis,
|
|
327
305
|
providers=providers,
|
|
328
306
|
storage=storage,
|
|
@@ -25,6 +25,20 @@ class Scope(BaseModel):
|
|
|
25
25
|
resource: str | None = None
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
class RouteScope(BaseModel):
|
|
29
|
+
"""Scope for route-level access control.
|
|
30
|
+
|
|
31
|
+
Defines which API routes can be accessed. The paths field
|
|
32
|
+
accepts single paths, lists of paths, or wildcards:
|
|
33
|
+
- Exact: "/v1/chat/completions"
|
|
34
|
+
- List: ["/v1/files*", "/v1/models*"]
|
|
35
|
+
- Prefix wildcard: "/v1/files*" matches "/v1/files" and all paths starting with "/v1/files"
|
|
36
|
+
- Full wildcard: "*"
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
paths: str | list[str]
|
|
40
|
+
|
|
41
|
+
|
|
28
42
|
def _mutually_exclusive(obj, a: str, b: str):
|
|
29
43
|
if getattr(obj, a) and getattr(obj, b):
|
|
30
44
|
raise ValueError(f"{a} and {b} are mutually exclusive")
|
|
@@ -105,3 +119,67 @@ class AccessRule(BaseModel):
|
|
|
105
119
|
elif self.unless:
|
|
106
120
|
parse_conditions([self.unless])
|
|
107
121
|
return self
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class RouteAccessRule(BaseModel):
|
|
125
|
+
"""Route-level access rule for controlling API route access.
|
|
126
|
+
|
|
127
|
+
This rule defines which API routes users can access based on their
|
|
128
|
+
attributes (roles, teams, etc). Rules are evaluated before resource-level
|
|
129
|
+
access control.
|
|
130
|
+
|
|
131
|
+
A rule defines either permit or forbid access to specific routes. The routes
|
|
132
|
+
are specified using the 'paths' field which can be:
|
|
133
|
+
- A single exact path: "/v1/chat/completions"
|
|
134
|
+
- A list of paths: ["/v1/files*", "/v1/models*"]
|
|
135
|
+
- A wildcard prefix: "/v1/files*" matches /v1/files and all paths starting with /v1/files
|
|
136
|
+
- Full wildcard: "*" matches all routes
|
|
137
|
+
|
|
138
|
+
Path normalization: Trailing slashes are automatically removed (e.g., /v1/files/ becomes /v1/files).
|
|
139
|
+
|
|
140
|
+
A rule may also specify a condition using 'when' or 'unless', with the same
|
|
141
|
+
constraints as resource-level rules:
|
|
142
|
+
- 'user with <attr-value> in <attr-name>'
|
|
143
|
+
- 'user with <attr-value> not in <attr-name>'
|
|
144
|
+
|
|
145
|
+
If no route_policy is configured, all routes are allowed.
|
|
146
|
+
If route_policy is configured, rules are tested in order to find a match.
|
|
147
|
+
|
|
148
|
+
Examples in yaml:
|
|
149
|
+
|
|
150
|
+
- permit:
|
|
151
|
+
paths: "/v1/chat/completions"
|
|
152
|
+
when: user with developer in roles
|
|
153
|
+
description: developers can access chat completions
|
|
154
|
+
|
|
155
|
+
- permit:
|
|
156
|
+
paths: ["/v1/files*", "/v1/models*"]
|
|
157
|
+
when: user with user in roles
|
|
158
|
+
description: users can access files and models routes
|
|
159
|
+
|
|
160
|
+
- permit:
|
|
161
|
+
paths: "*"
|
|
162
|
+
when: user with admin in roles
|
|
163
|
+
description: admins have access to all routes
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
permit: RouteScope | None = None
|
|
167
|
+
forbid: RouteScope | None = None
|
|
168
|
+
when: str | list[str] | None = None
|
|
169
|
+
unless: str | list[str] | None = None
|
|
170
|
+
description: str | None = None
|
|
171
|
+
|
|
172
|
+
@model_validator(mode="after")
|
|
173
|
+
def validate_rule_format(self) -> Self:
|
|
174
|
+
_require_one_of(self, "permit", "forbid")
|
|
175
|
+
_mutually_exclusive(self, "permit", "forbid")
|
|
176
|
+
_mutually_exclusive(self, "when", "unless")
|
|
177
|
+
if isinstance(self.when, list):
|
|
178
|
+
parse_conditions(self.when)
|
|
179
|
+
elif self.when:
|
|
180
|
+
parse_conditions([self.when])
|
|
181
|
+
if isinstance(self.unless, list):
|
|
182
|
+
parse_conditions(self.unless)
|
|
183
|
+
elif self.unless:
|
|
184
|
+
parse_conditions([self.unless])
|
|
185
|
+
return self
|
llama_stack/core/configure.py
CHANGED
|
@@ -16,7 +16,7 @@ from llama_stack.core.distribution import (
|
|
|
16
16
|
builtin_automatically_routed_apis,
|
|
17
17
|
get_provider_registry,
|
|
18
18
|
)
|
|
19
|
-
from llama_stack.core.stack import
|
|
19
|
+
from llama_stack.core.stack import cast_distro_name_to_string, replace_env_vars
|
|
20
20
|
from llama_stack.core.utils.dynamic import instantiate_class_type
|
|
21
21
|
from llama_stack.core.utils.prompt_for_config import prompt_for_config
|
|
22
22
|
from llama_stack.log import get_logger
|
|
@@ -200,4 +200,4 @@ def parse_and_maybe_upgrade_config(config_dict: dict[str, Any]) -> StackConfig:
|
|
|
200
200
|
config_dict["version"] = LLAMA_STACK_RUN_CONFIG_VERSION
|
|
201
201
|
|
|
202
202
|
processed_config_dict = replace_env_vars(config_dict)
|
|
203
|
-
return StackConfig(**
|
|
203
|
+
return StackConfig(**cast_distro_name_to_string(processed_config_dict))
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
5
|
# the root directory of this source tree.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
from llama_stack.core.connectors.connectors import ConnectorServiceConfig, ConnectorServiceImpl
|
|
8
8
|
|
|
9
|
-
__all__
|
|
9
|
+
__all__ = ["ConnectorServiceConfig", "ConnectorServiceImpl"]
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# This source code is licensed under the terms described in the LICENSE file in
|
|
5
|
+
# the root directory of this source tree.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from llama_stack.core.datatypes import StackConfig
|
|
12
|
+
from llama_stack.core.storage.kvstore import KVStore, kvstore_impl
|
|
13
|
+
from llama_stack.log import get_logger
|
|
14
|
+
from llama_stack.providers.utils.tools.mcp import get_mcp_server_info, list_mcp_tools
|
|
15
|
+
from llama_stack_api import (
|
|
16
|
+
Connector,
|
|
17
|
+
ConnectorNotFoundError,
|
|
18
|
+
Connectors,
|
|
19
|
+
ConnectorToolNotFoundError,
|
|
20
|
+
ConnectorType,
|
|
21
|
+
GetConnectorRequest,
|
|
22
|
+
GetConnectorToolRequest,
|
|
23
|
+
ListConnectorsResponse,
|
|
24
|
+
ListConnectorToolsRequest,
|
|
25
|
+
ListToolsResponse,
|
|
26
|
+
ToolDef,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
logger = get_logger(name=__name__, category="connectors")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ConnectorServiceConfig(BaseModel):
|
|
33
|
+
"""Configuration for the built-in connector service."""
|
|
34
|
+
|
|
35
|
+
config: StackConfig = Field(..., description="Stack run configuration for resolving persistence")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def get_provider_impl(config: ConnectorServiceConfig):
|
|
39
|
+
"""Get the connector service implementation."""
|
|
40
|
+
impl = ConnectorServiceImpl(config)
|
|
41
|
+
return impl
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
KEY_PREFIX = "connectors:v1:"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ConnectorServiceImpl(Connectors):
|
|
48
|
+
"""Built-in connector service implementation."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, config: ConnectorServiceConfig):
|
|
51
|
+
self.config = config
|
|
52
|
+
self.kvstore: KVStore
|
|
53
|
+
|
|
54
|
+
def _get_key(self, connector_id: str) -> str:
|
|
55
|
+
"""Get the KVStore key for a connector."""
|
|
56
|
+
return f"{KEY_PREFIX}{connector_id}"
|
|
57
|
+
|
|
58
|
+
async def initialize(self):
|
|
59
|
+
"""Initialize the connector service."""
|
|
60
|
+
|
|
61
|
+
# Use connectors store reference from run config
|
|
62
|
+
connectors_ref = self.config.config.storage.stores.connectors
|
|
63
|
+
if not connectors_ref:
|
|
64
|
+
raise ValueError("storage.stores.connectors must be configured in config")
|
|
65
|
+
self.kvstore = await kvstore_impl(connectors_ref)
|
|
66
|
+
|
|
67
|
+
async def register_connector(
|
|
68
|
+
self,
|
|
69
|
+
connector_id: str,
|
|
70
|
+
connector_type: ConnectorType,
|
|
71
|
+
url: str,
|
|
72
|
+
server_label: str | None = None,
|
|
73
|
+
server_name: str | None = None,
|
|
74
|
+
server_description: str | None = None,
|
|
75
|
+
) -> Connector:
|
|
76
|
+
"""Register a new connector"""
|
|
77
|
+
|
|
78
|
+
connector = Connector(
|
|
79
|
+
connector_id=connector_id,
|
|
80
|
+
connector_type=connector_type,
|
|
81
|
+
url=url,
|
|
82
|
+
server_label=server_label,
|
|
83
|
+
server_name=server_name,
|
|
84
|
+
server_description=server_description,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
key = self._get_key(connector_id)
|
|
88
|
+
existing_connector_json = await self.kvstore.get(key)
|
|
89
|
+
|
|
90
|
+
if existing_connector_json:
|
|
91
|
+
existing_connector = Connector.model_validate_json(existing_connector_json)
|
|
92
|
+
|
|
93
|
+
if connector == existing_connector:
|
|
94
|
+
logger.info(
|
|
95
|
+
"Connector %s already exists; skipping registration",
|
|
96
|
+
connector_id,
|
|
97
|
+
)
|
|
98
|
+
return existing_connector
|
|
99
|
+
|
|
100
|
+
await self.kvstore.set(key, json.dumps(connector.model_dump()))
|
|
101
|
+
|
|
102
|
+
return connector
|
|
103
|
+
|
|
104
|
+
async def unregister_connector(self, connector_id: str):
|
|
105
|
+
"""Unregister a connector."""
|
|
106
|
+
key = self._get_key(connector_id)
|
|
107
|
+
if not await self.kvstore.get(key):
|
|
108
|
+
return
|
|
109
|
+
await self.kvstore.delete(key)
|
|
110
|
+
|
|
111
|
+
async def get_connector(
|
|
112
|
+
self,
|
|
113
|
+
request: GetConnectorRequest,
|
|
114
|
+
authorization: str | None = None,
|
|
115
|
+
) -> Connector:
|
|
116
|
+
"""Get a connector by its ID."""
|
|
117
|
+
|
|
118
|
+
connector_json = await self.kvstore.get(self._get_key(request.connector_id))
|
|
119
|
+
if not connector_json:
|
|
120
|
+
raise ConnectorNotFoundError(request.connector_id)
|
|
121
|
+
connector = Connector.model_validate_json(connector_json)
|
|
122
|
+
|
|
123
|
+
server_info = await get_mcp_server_info(connector.url, authorization=authorization)
|
|
124
|
+
connector.server_name = server_info.name
|
|
125
|
+
connector.server_description = server_info.description
|
|
126
|
+
connector.server_version = server_info.version
|
|
127
|
+
return connector
|
|
128
|
+
|
|
129
|
+
async def list_connectors(self) -> ListConnectorsResponse:
|
|
130
|
+
"""List all connectors."""
|
|
131
|
+
connectors = []
|
|
132
|
+
for key in await self.kvstore.keys_in_range(start_key=KEY_PREFIX, end_key=KEY_PREFIX + "\uffff"):
|
|
133
|
+
connector_json = await self.kvstore.get(key)
|
|
134
|
+
if not connector_json:
|
|
135
|
+
continue
|
|
136
|
+
connector = Connector.model_validate_json(connector_json)
|
|
137
|
+
connectors.append(connector)
|
|
138
|
+
return ListConnectorsResponse(data=connectors)
|
|
139
|
+
|
|
140
|
+
async def get_connector_tool(self, request: GetConnectorToolRequest, authorization: str | None = None) -> ToolDef:
|
|
141
|
+
"""Get a tool from a connector."""
|
|
142
|
+
connector_tools = await self.list_connector_tools(
|
|
143
|
+
ListConnectorToolsRequest(connector_id=request.connector_id), authorization=authorization
|
|
144
|
+
)
|
|
145
|
+
for tool in connector_tools.data:
|
|
146
|
+
if tool.name == request.tool_name:
|
|
147
|
+
return tool
|
|
148
|
+
raise ConnectorToolNotFoundError(request.connector_id, request.tool_name)
|
|
149
|
+
|
|
150
|
+
async def list_connector_tools(
|
|
151
|
+
self, request: ListConnectorToolsRequest, authorization: str | None = None
|
|
152
|
+
) -> ListToolsResponse:
|
|
153
|
+
"""List tools from a connector."""
|
|
154
|
+
connector = await self.get_connector(
|
|
155
|
+
GetConnectorRequest(connector_id=request.connector_id), authorization=authorization
|
|
156
|
+
)
|
|
157
|
+
tools = await list_mcp_tools(endpoint=connector.url, authorization=authorization)
|
|
158
|
+
return ListToolsResponse(data=tools.data)
|
|
159
|
+
|
|
160
|
+
async def shutdown(self):
|
|
161
|
+
"""Shutdown the connector service."""
|
|
162
|
+
await self.kvstore.close()
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import secrets
|
|
8
8
|
import time
|
|
9
|
-
from typing import Any
|
|
9
|
+
from typing import Any
|
|
10
10
|
|
|
11
11
|
from pydantic import BaseModel, TypeAdapter
|
|
12
12
|
|
|
@@ -14,15 +14,21 @@ from llama_stack.core.datatypes import AccessRule, StackConfig
|
|
|
14
14
|
from llama_stack.core.storage.sqlstore.authorized_sqlstore import AuthorizedSqlStore
|
|
15
15
|
from llama_stack.core.storage.sqlstore.sqlstore import sqlstore_impl
|
|
16
16
|
from llama_stack.log import get_logger
|
|
17
|
-
from llama_stack_api import (
|
|
17
|
+
from llama_stack_api.conversations import (
|
|
18
|
+
AddItemsRequest,
|
|
18
19
|
Conversation,
|
|
19
20
|
ConversationDeletedResource,
|
|
20
21
|
ConversationItem,
|
|
21
22
|
ConversationItemDeletedResource,
|
|
22
|
-
ConversationItemInclude,
|
|
23
23
|
ConversationItemList,
|
|
24
24
|
Conversations,
|
|
25
|
-
|
|
25
|
+
CreateConversationRequest,
|
|
26
|
+
DeleteConversationRequest,
|
|
27
|
+
DeleteItemRequest,
|
|
28
|
+
GetConversationRequest,
|
|
29
|
+
ListItemsRequest,
|
|
30
|
+
RetrieveItemRequest,
|
|
31
|
+
UpdateConversationRequest,
|
|
26
32
|
)
|
|
27
33
|
from llama_stack_api.internal.sqlstore import ColumnDefinition, ColumnType
|
|
28
34
|
|
|
@@ -85,9 +91,7 @@ class ConversationServiceImpl(Conversations):
|
|
|
85
91
|
},
|
|
86
92
|
)
|
|
87
93
|
|
|
88
|
-
async def create_conversation(
|
|
89
|
-
self, items: list[ConversationItem] | None = None, metadata: Metadata | None = None
|
|
90
|
-
) -> Conversation:
|
|
94
|
+
async def create_conversation(self, request: CreateConversationRequest) -> Conversation:
|
|
91
95
|
"""Create a conversation."""
|
|
92
96
|
random_bytes = secrets.token_bytes(24)
|
|
93
97
|
conversation_id = f"conv_{random_bytes.hex()}"
|
|
@@ -97,7 +101,7 @@ class ConversationServiceImpl(Conversations):
|
|
|
97
101
|
"id": conversation_id,
|
|
98
102
|
"created_at": created_at,
|
|
99
103
|
"items": [],
|
|
100
|
-
"metadata": metadata,
|
|
104
|
+
"metadata": request.metadata,
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
await self.sql_store.insert(
|
|
@@ -105,9 +109,9 @@ class ConversationServiceImpl(Conversations):
|
|
|
105
109
|
data=record_data,
|
|
106
110
|
)
|
|
107
111
|
|
|
108
|
-
if items:
|
|
112
|
+
if request.items:
|
|
109
113
|
item_records = []
|
|
110
|
-
for item in items:
|
|
114
|
+
for item in request.items:
|
|
111
115
|
item_dict = item.model_dump()
|
|
112
116
|
item_id = self._get_or_generate_item_id(item, item_dict)
|
|
113
117
|
|
|
@@ -125,38 +129,38 @@ class ConversationServiceImpl(Conversations):
|
|
|
125
129
|
conversation = Conversation(
|
|
126
130
|
id=conversation_id,
|
|
127
131
|
created_at=created_at,
|
|
128
|
-
metadata=metadata,
|
|
132
|
+
metadata=request.metadata,
|
|
129
133
|
object="conversation",
|
|
130
134
|
)
|
|
131
135
|
|
|
132
136
|
logger.debug(f"Created conversation {conversation_id}")
|
|
133
137
|
return conversation
|
|
134
138
|
|
|
135
|
-
async def get_conversation(self,
|
|
139
|
+
async def get_conversation(self, request: GetConversationRequest) -> Conversation:
|
|
136
140
|
"""Get a conversation with the given ID."""
|
|
137
|
-
record = await self.sql_store.fetch_one(table="openai_conversations", where={"id": conversation_id})
|
|
141
|
+
record = await self.sql_store.fetch_one(table="openai_conversations", where={"id": request.conversation_id})
|
|
138
142
|
|
|
139
143
|
if record is None:
|
|
140
|
-
raise ValueError(f"Conversation {conversation_id} not found")
|
|
144
|
+
raise ValueError(f"Conversation {request.conversation_id} not found")
|
|
141
145
|
|
|
142
146
|
return Conversation(
|
|
143
147
|
id=record["id"], created_at=record["created_at"], metadata=record.get("metadata"), object="conversation"
|
|
144
148
|
)
|
|
145
149
|
|
|
146
|
-
async def update_conversation(self, conversation_id: str,
|
|
150
|
+
async def update_conversation(self, conversation_id: str, request: UpdateConversationRequest) -> Conversation:
|
|
147
151
|
"""Update a conversation's metadata with the given ID"""
|
|
148
152
|
await self.sql_store.update(
|
|
149
|
-
table="openai_conversations", data={"metadata": metadata}, where={"id": conversation_id}
|
|
153
|
+
table="openai_conversations", data={"metadata": request.metadata}, where={"id": conversation_id}
|
|
150
154
|
)
|
|
151
155
|
|
|
152
|
-
return await self.get_conversation(conversation_id)
|
|
156
|
+
return await self.get_conversation(GetConversationRequest(conversation_id=conversation_id))
|
|
153
157
|
|
|
154
|
-
async def openai_delete_conversation(self,
|
|
158
|
+
async def openai_delete_conversation(self, request: DeleteConversationRequest) -> ConversationDeletedResource:
|
|
155
159
|
"""Delete a conversation with the given ID."""
|
|
156
|
-
await self.sql_store.delete(table="openai_conversations", where={"id": conversation_id})
|
|
160
|
+
await self.sql_store.delete(table="openai_conversations", where={"id": request.conversation_id})
|
|
157
161
|
|
|
158
|
-
logger.debug(f"Deleted conversation {conversation_id}")
|
|
159
|
-
return ConversationDeletedResource(id=conversation_id)
|
|
162
|
+
logger.debug(f"Deleted conversation {request.conversation_id}")
|
|
163
|
+
return ConversationDeletedResource(id=request.conversation_id)
|
|
160
164
|
|
|
161
165
|
def _validate_conversation_id(self, conversation_id: str) -> None:
|
|
162
166
|
"""Validate conversation ID format."""
|
|
@@ -180,16 +184,16 @@ class ConversationServiceImpl(Conversations):
|
|
|
180
184
|
async def _get_validated_conversation(self, conversation_id: str) -> Conversation:
|
|
181
185
|
"""Validate conversation ID and return the conversation if it exists."""
|
|
182
186
|
self._validate_conversation_id(conversation_id)
|
|
183
|
-
return await self.get_conversation(conversation_id)
|
|
187
|
+
return await self.get_conversation(GetConversationRequest(conversation_id=conversation_id))
|
|
184
188
|
|
|
185
|
-
async def add_items(self, conversation_id: str,
|
|
189
|
+
async def add_items(self, conversation_id: str, request: AddItemsRequest) -> ConversationItemList:
|
|
186
190
|
"""Create (add) items to a conversation."""
|
|
187
191
|
await self._get_validated_conversation(conversation_id)
|
|
188
192
|
|
|
189
193
|
created_items = []
|
|
190
194
|
base_time = int(time.time())
|
|
191
195
|
|
|
192
|
-
for i, item in enumerate(items):
|
|
196
|
+
for i, item in enumerate(request.items):
|
|
193
197
|
item_dict = item.model_dump()
|
|
194
198
|
item_id = self._get_or_generate_item_id(item, item_dict)
|
|
195
199
|
|
|
@@ -224,48 +228,47 @@ class ConversationServiceImpl(Conversations):
|
|
|
224
228
|
has_more=False,
|
|
225
229
|
)
|
|
226
230
|
|
|
227
|
-
async def retrieve(self,
|
|
231
|
+
async def retrieve(self, request: RetrieveItemRequest) -> ConversationItem:
|
|
228
232
|
"""Retrieve a conversation item."""
|
|
229
|
-
if not conversation_id:
|
|
230
|
-
raise ValueError(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
+
if not request.conversation_id:
|
|
234
|
+
raise ValueError(
|
|
235
|
+
f"Expected a non-empty value for `conversation_id` but received {request.conversation_id!r}"
|
|
236
|
+
)
|
|
237
|
+
if not request.item_id:
|
|
238
|
+
raise ValueError(f"Expected a non-empty value for `item_id` but received {request.item_id!r}")
|
|
233
239
|
|
|
234
240
|
# Get item from conversation_items table
|
|
235
241
|
record = await self.sql_store.fetch_one(
|
|
236
|
-
table="conversation_items", where={"id": item_id, "conversation_id": conversation_id}
|
|
242
|
+
table="conversation_items", where={"id": request.item_id, "conversation_id": request.conversation_id}
|
|
237
243
|
)
|
|
238
244
|
|
|
239
245
|
if record is None:
|
|
240
|
-
raise ValueError(f"Item {item_id} not found in conversation {conversation_id}")
|
|
246
|
+
raise ValueError(f"Item {request.item_id} not found in conversation {request.conversation_id}")
|
|
241
247
|
|
|
242
248
|
adapter: TypeAdapter[ConversationItem] = TypeAdapter(ConversationItem)
|
|
243
249
|
return adapter.validate_python(record["item_data"])
|
|
244
250
|
|
|
245
|
-
async def list_items(
|
|
246
|
-
self,
|
|
247
|
-
conversation_id: str,
|
|
248
|
-
after: str | None = None,
|
|
249
|
-
include: list[ConversationItemInclude] | None = None,
|
|
250
|
-
limit: int | None = None,
|
|
251
|
-
order: Literal["asc", "desc"] | None = None,
|
|
252
|
-
) -> ConversationItemList:
|
|
251
|
+
async def list_items(self, request: ListItemsRequest) -> ConversationItemList:
|
|
253
252
|
"""List items in the conversation."""
|
|
254
|
-
if not conversation_id:
|
|
255
|
-
raise ValueError(
|
|
253
|
+
if not request.conversation_id:
|
|
254
|
+
raise ValueError(
|
|
255
|
+
f"Expected a non-empty value for `conversation_id` but received {request.conversation_id!r}"
|
|
256
|
+
)
|
|
256
257
|
|
|
257
258
|
# check if conversation exists
|
|
258
|
-
await self.get_conversation(conversation_id)
|
|
259
|
+
await self.get_conversation(GetConversationRequest(conversation_id=request.conversation_id))
|
|
259
260
|
|
|
260
|
-
result = await self.sql_store.fetch_all(
|
|
261
|
+
result = await self.sql_store.fetch_all(
|
|
262
|
+
table="conversation_items", where={"conversation_id": request.conversation_id}
|
|
263
|
+
)
|
|
261
264
|
records = result.data
|
|
262
265
|
|
|
263
|
-
if order is not None and order == "asc":
|
|
266
|
+
if request.order is not None and request.order == "asc":
|
|
264
267
|
records.sort(key=lambda x: x["created_at"])
|
|
265
268
|
else:
|
|
266
269
|
records.sort(key=lambda x: x["created_at"], reverse=True)
|
|
267
270
|
|
|
268
|
-
actual_limit = limit or 20
|
|
271
|
+
actual_limit = request.limit or 20
|
|
269
272
|
|
|
270
273
|
records = records[:actual_limit]
|
|
271
274
|
items = [record["item_data"] for record in records]
|
|
@@ -283,30 +286,30 @@ class ConversationServiceImpl(Conversations):
|
|
|
283
286
|
has_more=False,
|
|
284
287
|
)
|
|
285
288
|
|
|
286
|
-
async def openai_delete_conversation_item(
|
|
287
|
-
self, conversation_id: str, item_id: str
|
|
288
|
-
) -> ConversationItemDeletedResource:
|
|
289
|
+
async def openai_delete_conversation_item(self, request: DeleteItemRequest) -> ConversationItemDeletedResource:
|
|
289
290
|
"""Delete a conversation item."""
|
|
290
|
-
if not conversation_id:
|
|
291
|
-
raise ValueError(
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
if not request.conversation_id:
|
|
292
|
+
raise ValueError(
|
|
293
|
+
f"Expected a non-empty value for `conversation_id` but received {request.conversation_id!r}"
|
|
294
|
+
)
|
|
295
|
+
if not request.item_id:
|
|
296
|
+
raise ValueError(f"Expected a non-empty value for `item_id` but received {request.item_id!r}")
|
|
294
297
|
|
|
295
|
-
_ = await self._get_validated_conversation(conversation_id)
|
|
298
|
+
_ = await self._get_validated_conversation(request.conversation_id)
|
|
296
299
|
|
|
297
300
|
record = await self.sql_store.fetch_one(
|
|
298
|
-
table="conversation_items", where={"id": item_id, "conversation_id": conversation_id}
|
|
301
|
+
table="conversation_items", where={"id": request.item_id, "conversation_id": request.conversation_id}
|
|
299
302
|
)
|
|
300
303
|
|
|
301
304
|
if record is None:
|
|
302
|
-
raise ValueError(f"Item {item_id} not found in conversation {conversation_id}")
|
|
305
|
+
raise ValueError(f"Item {request.item_id} not found in conversation {request.conversation_id}")
|
|
303
306
|
|
|
304
307
|
await self.sql_store.delete(
|
|
305
|
-
table="conversation_items", where={"id": item_id, "conversation_id": conversation_id}
|
|
308
|
+
table="conversation_items", where={"id": request.item_id, "conversation_id": request.conversation_id}
|
|
306
309
|
)
|
|
307
310
|
|
|
308
|
-
logger.debug(f"Deleted item {item_id} from conversation {conversation_id}")
|
|
309
|
-
return ConversationItemDeletedResource(id=item_id)
|
|
311
|
+
logger.debug(f"Deleted item {request.item_id} from conversation {request.conversation_id}")
|
|
312
|
+
return ConversationItemDeletedResource(id=request.item_id)
|
|
310
313
|
|
|
311
314
|
async def shutdown(self) -> None:
|
|
312
315
|
pass
|