From 2232bfa8b551905e2b9c5a4ddade07a6903824c1 Mon Sep 17 00:00:00 2001 From: raghotham Date: Tue, 20 Aug 2024 19:01:18 -0700 Subject: [PATCH] RFC-0001-The-Llama-Stack (#8) * RFC-0001-The-Llama-Stack * Add OpenAPI generation utility, update SPEC to reflect latest types * First cut at an observability API * llama3_1 -> llama3 --------- Co-authored-by: Ashwin Bharambe --- llama_toolchain/evaluations/api/endpoints.py | 6 +- llama_toolchain/memory/api/endpoints.py | 6 +- llama_toolchain/observability/__init__.py | 5 + llama_toolchain/observability/api/__init__.py | 8 + .../observability/api/datatypes.py | 80 + .../observability/api/endpoints.py | 108 + .../post_training/api/endpoints.py | 4 +- .../reward_scoring/api/endpoints.py | 2 +- llama_toolchain/stack.py | 30 + .../api/endpoints.py | 2 +- .../agentic-system.png | Bin 0 -> 130647 bytes .../llama-stack-spec.html | 5358 +++++++++++++++++ .../llama-stack-spec.yaml | 3339 ++++++++++ .../llama-stack.png | Bin 0 -> 72643 bytes .../model-lifecycle.png | Bin 0 -> 17824 bytes rfcs/RFC-0001-llama-stack.md | 86 + rfcs/openapi_generator/README.md | 9 + rfcs/openapi_generator/generate.py | 111 + .../run_openapi_generator.sh | 33 + 19 files changed, 9177 insertions(+), 10 deletions(-) create mode 100644 llama_toolchain/observability/__init__.py create mode 100644 llama_toolchain/observability/api/__init__.py create mode 100644 llama_toolchain/observability/api/datatypes.py create mode 100644 llama_toolchain/observability/api/endpoints.py create mode 100644 llama_toolchain/stack.py create mode 100644 rfcs/RFC-0001-llama-stack-assets/agentic-system.png create mode 100644 rfcs/RFC-0001-llama-stack-assets/llama-stack-spec.html create mode 100644 rfcs/RFC-0001-llama-stack-assets/llama-stack-spec.yaml create mode 100644 rfcs/RFC-0001-llama-stack-assets/llama-stack.png create mode 100644 rfcs/RFC-0001-llama-stack-assets/model-lifecycle.png create mode 100644 rfcs/RFC-0001-llama-stack.md create mode 100644 rfcs/openapi_generator/README.md create mode 100644 rfcs/openapi_generator/generate.py create mode 100644 rfcs/openapi_generator/run_openapi_generator.sh diff --git a/llama_toolchain/evaluations/api/endpoints.py b/llama_toolchain/evaluations/api/endpoints.py index fd5b68bbe..25fb570f7 100644 --- a/llama_toolchain/evaluations/api/endpoints.py +++ b/llama_toolchain/evaluations/api/endpoints.py @@ -60,19 +60,19 @@ class EvaluationJobArtifactsResponse(BaseModel): class Evaluations(Protocol): @webmethod(route="/evaluate/text_generation/") - def post_evaluate_text_generation( + def evaluate_text_generation( self, request: EvaluateTextGenerationRequest, ) -> EvaluationJob: ... @webmethod(route="/evaluate/question_answering/") - def post_evaluate_question_answering( + def evaluate_question_answering( self, request: EvaluateQuestionAnsweringRequest, ) -> EvaluationJob: ... @webmethod(route="/evaluate/summarization/") - def post_evaluate_summarization( + def evaluate_summarization( self, request: EvaluateSummarizationRequest, ) -> EvaluationJob: ... diff --git a/llama_toolchain/memory/api/endpoints.py b/llama_toolchain/memory/api/endpoints.py index 4261afa89..d8ac0e90c 100644 --- a/llama_toolchain/memory/api/endpoints.py +++ b/llama_toolchain/memory/api/endpoints.py @@ -13,7 +13,7 @@ from .datatypes import * # noqa: F403 class MemoryBanks(Protocol): @webmethod(route="/memory_banks/create") - def post_create_memory_bank( + def create_memory_bank( self, bank_id: str, bank_name: str, @@ -33,14 +33,14 @@ class MemoryBanks(Protocol): ) -> str: ... @webmethod(route="/memory_bank/insert") - def post_insert_memory_documents( + def insert_memory_documents( self, bank_id: str, documents: List[MemoryBankDocument], ) -> None: ... @webmethod(route="/memory_bank/update") - def post_update_memory_documents( + def update_memory_documents( self, bank_id: str, documents: List[MemoryBankDocument], diff --git a/llama_toolchain/observability/__init__.py b/llama_toolchain/observability/__init__.py new file mode 100644 index 000000000..756f351d8 --- /dev/null +++ b/llama_toolchain/observability/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. diff --git a/llama_toolchain/observability/api/__init__.py b/llama_toolchain/observability/api/__init__.py new file mode 100644 index 000000000..647bd4a5f --- /dev/null +++ b/llama_toolchain/observability/api/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +from .datatypes import * # noqa: F401 F403 +from .endpoints import * # noqa: F401 F403 diff --git a/llama_toolchain/observability/api/datatypes.py b/llama_toolchain/observability/api/datatypes.py new file mode 100644 index 000000000..42f95b64c --- /dev/null +++ b/llama_toolchain/observability/api/datatypes.py @@ -0,0 +1,80 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +from datetime import datetime +from enum import Enum + +from typing import Any, Dict, Optional, Union + +from llama_models.schema_utils import json_schema_type + +from pydantic import BaseModel + + +@json_schema_type +class ExperimentStatus(Enum): + NOT_STARTED = "not_started" + RUNNING = "running" + COMPLETED = "completed" + FAILED = "failed" + + +@json_schema_type +class Experiment(BaseModel): + id: str + name: str + status: ExperimentStatus + created_at: datetime + updated_at: datetime + metadata: Dict[str, Any] + + +@json_schema_type +class Run(BaseModel): + id: str + experiment_id: str + status: str + started_at: datetime + ended_at: Optional[datetime] + metadata: Dict[str, Any] + + +@json_schema_type +class Metric(BaseModel): + name: str + value: Union[float, int, str, bool] + timestamp: datetime + run_id: str + + +@json_schema_type +class Log(BaseModel): + message: str + level: str + timestamp: datetime + additional_info: Dict[str, Any] + + +@json_schema_type +class ArtifactType(Enum): + MODEL = "model" + DATASET = "dataset" + CHECKPOINT = "checkpoint" + PLOT = "plot" + METRIC = "metric" + CONFIG = "config" + CODE = "code" + OTHER = "other" + + +@json_schema_type +class Artifact(BaseModel): + id: str + name: str + type: ArtifactType + size: int + created_at: datetime + metadata: Dict[str, Any] diff --git a/llama_toolchain/observability/api/endpoints.py b/llama_toolchain/observability/api/endpoints.py new file mode 100644 index 000000000..3f993ac2d --- /dev/null +++ b/llama_toolchain/observability/api/endpoints.py @@ -0,0 +1,108 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +from datetime import datetime +from typing import Any, Dict, List, Optional, Protocol + +from llama_models.schema_utils import json_schema_type, webmethod +from pydantic import BaseModel +from llama_models.llama3.api.datatypes import * # noqa: F403 +from .datatypes import * # noqa: F403 + + +@json_schema_type +class CreateExperimentRequest(BaseModel): + name: str + metadata: Optional[Dict[str, Any]] = None + + +@json_schema_type +class UpdateExperimentRequest(BaseModel): + experiment_id: str + status: Optional[ExperimentStatus] = None + metadata: Optional[Dict[str, Any]] = None + + +@json_schema_type +class CreateRunRequest(BaseModel): + experiment_id: str + metadata: Optional[Dict[str, Any]] = None + + +@json_schema_type +class UpdateRunRequest(BaseModel): + run_id: str + status: Optional[str] = None + ended_at: Optional[datetime] = None + metadata: Optional[Dict[str, Any]] = None + + +@json_schema_type +class LogMetricsRequest(BaseModel): + run_id: str + metrics: List[Metric] + + +@json_schema_type +class LogMessagesRequest(BaseModel): + logs: List[Log] + run_id: Optional[str] = None + + +@json_schema_type +class UploadArtifactRequest(BaseModel): + experiment_id: str + name: str + artifact_type: str + content: bytes + metadata: Optional[Dict[str, Any]] = None + + +@json_schema_type +class LogSearchRequest(BaseModel): + query: str + filters: Optional[Dict[str, Any]] = None + + +class Observability(Protocol): + @webmethod(route="/experiments/create") + def create_experiment(self, request: CreateExperimentRequest) -> Experiment: ... + + @webmethod(route="/experiments/list") + def list_experiments(self) -> List[Experiment]: ... + + @webmethod(route="/experiments/get") + def get_experiment(self, experiment_id: str) -> Experiment: ... + + @webmethod(route="/experiments/update") + def update_experiment(self, request: UpdateExperimentRequest) -> Experiment: ... + + @webmethod(route="/experiments/create_run") + def create_run(self, request: CreateRunRequest) -> Run: ... + + @webmethod(route="/runs/update") + def update_run(self, request: UpdateRunRequest) -> Run: ... + + @webmethod(route="/runs/log_metrics") + def log_metrics(self, request: LogMetricsRequest) -> None: ... + + @webmethod(route="/runs/metrics", method="GET") + def get_metrics(self, run_id: str) -> List[Metric]: ... + + @webmethod(route="/logging/log_messages") + def log_messages(self, request: LogMessagesRequest) -> None: ... + + @webmethod(route="/logging/get_logs") + def get_logs(self, request: LogSearchRequest) -> List[Log]: ... + + @webmethod(route="/experiments/artifacts/upload") + def upload_artifact(self, request: UploadArtifactRequest) -> Artifact: ... + + @webmethod(route="/experiments/artifacts/get") + def list_artifacts(self, experiment_id: str) -> List[Artifact]: ... + + @webmethod(route="/artifacts/get") + def get_artifact(self, artifact_id: str) -> Artifact: ... diff --git a/llama_toolchain/post_training/api/endpoints.py b/llama_toolchain/post_training/api/endpoints.py index e451def17..f0536ee4c 100644 --- a/llama_toolchain/post_training/api/endpoints.py +++ b/llama_toolchain/post_training/api/endpoints.py @@ -95,13 +95,13 @@ class PostTrainingJobArtifactsResponse(BaseModel): class PostTraining(Protocol): @webmethod(route="/post_training/supervised_fine_tune") - def post_supervised_fine_tune( + def supervised_fine_tune( self, request: PostTrainingSFTRequest, ) -> PostTrainingJob: ... @webmethod(route="/post_training/preference_optimize") - def post_preference_optimize( + def preference_optimize( self, request: PostTrainingRLHFRequest, ) -> PostTrainingJob: ... diff --git a/llama_toolchain/reward_scoring/api/endpoints.py b/llama_toolchain/reward_scoring/api/endpoints.py index 0a7327a9b..657e7b325 100644 --- a/llama_toolchain/reward_scoring/api/endpoints.py +++ b/llama_toolchain/reward_scoring/api/endpoints.py @@ -27,7 +27,7 @@ class RewardScoringResponse(BaseModel): class RewardScoring(Protocol): @webmethod(route="/reward_scoring/score") - def post_score( + def reward_score( self, request: RewardScoringRequest, ) -> Union[RewardScoringResponse]: ... diff --git a/llama_toolchain/stack.py b/llama_toolchain/stack.py new file mode 100644 index 000000000..88a54976c --- /dev/null +++ b/llama_toolchain/stack.py @@ -0,0 +1,30 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +from llama_models.llama3.api.datatypes import * # noqa: F403 +from llama_toolchain.agentic_system.api import * # noqa: F403 +from llama_toolchain.dataset.api import * # noqa: F403 +from llama_toolchain.evaluations.api import * # noqa: F403 +from llama_toolchain.inference.api import * # noqa: F403 +from llama_toolchain.memory.api import * # noqa: F403 +from llama_toolchain.observability.api import * # noqa: F403 +from llama_toolchain.post_training.api import * # noqa: F403 +from llama_toolchain.reward_scoring.api import * # noqa: F403 +from llama_toolchain.synthetic_data_generation.api import * # noqa: F403 + + +class LlamaStack( + Inference, + AgenticSystem, + RewardScoring, + SyntheticDataGeneration, + Datasets, + Observability, + PostTraining, + MemoryBanks, + Evaluations, +): + pass diff --git a/llama_toolchain/synthetic_data_generation/api/endpoints.py b/llama_toolchain/synthetic_data_generation/api/endpoints.py index 91585a943..d6b9c83d5 100644 --- a/llama_toolchain/synthetic_data_generation/api/endpoints.py +++ b/llama_toolchain/synthetic_data_generation/api/endpoints.py @@ -34,7 +34,7 @@ class SyntheticDataGenerationResponse(BaseModel): class SyntheticDataGeneration(Protocol): @webmethod(route="/synthetic_data_generation/generate") - def post_generate( + def synthetic_data_generate( self, request: SyntheticDataGenerationRequest, ) -> Union[SyntheticDataGenerationResponse]: ... diff --git a/rfcs/RFC-0001-llama-stack-assets/agentic-system.png b/rfcs/RFC-0001-llama-stack-assets/agentic-system.png new file mode 100644 index 0000000000000000000000000000000000000000..c452bcdd1ea94510ecdee9195d9ac346797d5622 GIT binary patch literal 130647 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
IJ8q<_d7q5EtXp}t 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

d&7+K)X9)@Q!-3%&5YZ=98X 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

UH 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 + + + + + + OpenAPI specification + + + + + + + +

+ + + diff --git a/rfcs/RFC-0001-llama-stack-assets/llama-stack-spec.yaml b/rfcs/RFC-0001-llama-stack-assets/llama-stack-spec.yaml new file mode 100644 index 000000000..837036811 --- /dev/null +++ b/rfcs/RFC-0001-llama-stack-assets/llama-stack-spec.yaml @@ -0,0 +1,3339 @@ +components: + responses: {} + schemas: + AgenticSystemCreateRequest: + additionalProperties: false + properties: + instance_config: + $ref: '#/components/schemas/AgenticSystemInstanceConfig' + model: + type: string + required: + - model + - instance_config + type: object + AgenticSystemCreateResponse: + additionalProperties: false + properties: + system_id: + type: string + required: + - system_id + type: object + AgenticSystemInstanceConfig: + additionalProperties: false + properties: + available_tools: + items: + $ref: '#/components/schemas/AgenticSystemToolDefinition' + type: array + debug_prefix_messages: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + input_shields: + items: + $ref: '#/components/schemas/ShieldDefinition' + type: array + instructions: + type: string + output_shields: + items: + $ref: '#/components/schemas/ShieldDefinition' + type: array + quantization_config: + oneOf: + - $ref: '#/components/schemas/Bf16QuantizationConfig' + - $ref: '#/components/schemas/Fp8QuantizationConfig' + sampling_params: + $ref: '#/components/schemas/SamplingParams' + tool_prompt_format: + $ref: '#/components/schemas/ToolPromptFormat' + required: + - instructions + type: object + AgenticSystemSessionCreateRequest: + additionalProperties: false + properties: + session_name: + type: string + system_id: + type: string + required: + - system_id + - session_name + type: object + AgenticSystemSessionCreateResponse: + additionalProperties: false + properties: + session_id: + type: string + required: + - session_id + type: object + AgenticSystemStepResponse: + additionalProperties: false + properties: + step: + oneOf: + - $ref: '#/components/schemas/InferenceStep' + - $ref: '#/components/schemas/ToolExecutionStep' + - $ref: '#/components/schemas/ShieldCallStep' + - $ref: '#/components/schemas/MemoryRetrievalStep' + required: + - step + type: object + AgenticSystemToolDefinition: + additionalProperties: false + properties: + description: + type: string + execution_config: + $ref: '#/components/schemas/RestAPIExecutionConfig' + input_shields: + items: + $ref: '#/components/schemas/ShieldDefinition' + type: array + output_shields: + items: + $ref: '#/components/schemas/ShieldDefinition' + type: array + parameters: + additionalProperties: + $ref: '#/components/schemas/ToolParamDefinition' + type: object + tool_name: + oneOf: + - $ref: '#/components/schemas/BuiltinTool' + - type: string + required: + - tool_name + type: object + AgenticSystemTurnCreateRequest: + additionalProperties: false + properties: + messages: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + type: array + override_config: + $ref: '#/components/schemas/AgenticSystemInstanceConfig' + session_id: + type: string + stream: + type: boolean + system_id: + type: string + required: + - system_id + - session_id + - messages + type: object + AgenticSystemTurnResponseStreamChunk: + description: Server side event (SSE) stream of these events + Artifact: + additionalProperties: false + properties: + created_at: + format: date-time + type: string + id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + name: + type: string + size: + type: integer + type: + $ref: '#/components/schemas/ArtifactType' + required: + - id + - name + - type + - size + - created_at + - metadata + type: object + ArtifactType: + enum: + - model + - dataset + - checkpoint + - plot + - metric + - config + - code + - other + type: string + Attachment: + additionalProperties: false + properties: + mime_type: + type: string + url: + $ref: '#/components/schemas/URL' + required: + - url + - mime_type + type: object + BatchChatCompletionRequest: + additionalProperties: false + properties: + available_tools: + items: + $ref: '#/components/schemas/ToolDefinition' + type: array + logprobs: + additionalProperties: false + properties: + top_k: + type: integer + type: object + messages_batch: + items: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + type: array + model: + type: string + quantization_config: + oneOf: + - $ref: '#/components/schemas/Bf16QuantizationConfig' + - $ref: '#/components/schemas/Fp8QuantizationConfig' + sampling_params: + $ref: '#/components/schemas/SamplingParams' + required: + - model + - messages_batch + type: object + BatchChatCompletionResponse: + additionalProperties: false + properties: + completion_message_batch: + items: + $ref: '#/components/schemas/CompletionMessage' + type: array + required: + - completion_message_batch + type: object + BatchCompletionRequest: + additionalProperties: false + properties: + content_batch: + items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + type: array + logprobs: + additionalProperties: false + properties: + top_k: + type: integer + type: object + model: + type: string + quantization_config: + oneOf: + - $ref: '#/components/schemas/Bf16QuantizationConfig' + - $ref: '#/components/schemas/Fp8QuantizationConfig' + sampling_params: + $ref: '#/components/schemas/SamplingParams' + required: + - model + - content_batch + type: object + BatchCompletionResponse: + additionalProperties: false + properties: + completion_message_batch: + items: + $ref: '#/components/schemas/CompletionMessage' + type: array + required: + - completion_message_batch + type: object + Bf16QuantizationConfig: + additionalProperties: false + properties: + type: + const: bf16 + type: string + required: + - type + type: object + BuiltinShield: + enum: + - llama_guard + - code_scanner_guard + - third_party_shield + - injection_shield + - jailbreak_shield + type: string + BuiltinTool: + enum: + - brave_search + - wolfram_alpha + - photogen + - code_interpreter + type: string + ChatCompletionRequest: + additionalProperties: false + properties: + available_tools: + items: + $ref: '#/components/schemas/ToolDefinition' + type: array + logprobs: + additionalProperties: false + properties: + top_k: + type: integer + type: object + messages: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + model: + type: string + quantization_config: + oneOf: + - $ref: '#/components/schemas/Bf16QuantizationConfig' + - $ref: '#/components/schemas/Fp8QuantizationConfig' + sampling_params: + $ref: '#/components/schemas/SamplingParams' + stream: + type: boolean + required: + - model + - messages + type: object + ChatCompletionResponseEvent: + additionalProperties: false + properties: + delta: + oneOf: + - type: string + - $ref: '#/components/schemas/ToolCallDelta' + event_type: + $ref: '#/components/schemas/ChatCompletionResponseEventType' + logprobs: + items: + $ref: '#/components/schemas/TokenLogProbs' + type: array + stop_reason: + $ref: '#/components/schemas/StopReason' + required: + - event_type + - delta + title: Chat completion response event. + type: object + ChatCompletionResponseEventType: + enum: + - start + - complete + - progress + type: string + ChatCompletionResponseStreamChunk: + additionalProperties: false + properties: + event: + $ref: '#/components/schemas/ChatCompletionResponseEvent' + required: + - event + title: SSE-stream of these events. + type: object + Checkpoint: + description: Checkpoint created during training runs + CompletionMessage: + additionalProperties: false + properties: + content: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + role: + const: assistant + type: string + stop_reason: + $ref: '#/components/schemas/StopReason' + tool_calls: + items: + $ref: '#/components/schemas/ToolCall' + type: array + required: + - role + - content + - stop_reason + - tool_calls + type: object + CompletionRequest: + additionalProperties: false + properties: + content: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + logprobs: + additionalProperties: false + properties: + top_k: + type: integer + type: object + model: + type: string + quantization_config: + oneOf: + - $ref: '#/components/schemas/Bf16QuantizationConfig' + - $ref: '#/components/schemas/Fp8QuantizationConfig' + sampling_params: + $ref: '#/components/schemas/SamplingParams' + stream: + type: boolean + required: + - model + - content + type: object + CompletionResponseStreamChunk: + additionalProperties: false + properties: + delta: + type: string + logprobs: + items: + $ref: '#/components/schemas/TokenLogProbs' + type: array + stop_reason: + $ref: '#/components/schemas/StopReason' + required: + - delta + title: streamed completion response. + type: object + CreateDatasetRequest: + additionalProperties: false + properties: + dataset: + $ref: '#/components/schemas/TrainEvalDataset' + uuid: + type: string + required: + - uuid + - dataset + title: Request to create a dataset. + type: object + CreateExperimentRequest: + additionalProperties: false + properties: + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + name: + type: string + required: + - name + type: object + CreateRunRequest: + additionalProperties: false + properties: + experiment_id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + required: + - experiment_id + type: object + DPOAlignmentConfig: + additionalProperties: false + properties: + epsilon: + type: number + gamma: + type: number + reward_clip: + type: number + reward_scale: + type: number + required: + - reward_scale + - reward_clip + - epsilon + - gamma + type: object + DialogGenerations: + additionalProperties: false + properties: + dialog: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + sampled_generations: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + required: + - dialog + - sampled_generations + type: object + DoraFinetuningConfig: + additionalProperties: false + properties: + alpha: + type: integer + apply_lora_to_mlp: + type: boolean + apply_lora_to_output: + type: boolean + lora_attn_modules: + items: + type: string + type: array + rank: + type: integer + required: + - lora_attn_modules + - apply_lora_to_mlp + - apply_lora_to_output + - rank + - alpha + type: object + EvaluateQuestionAnsweringRequest: + additionalProperties: false + properties: + checkpoint: + $ref: '#/components/schemas/Checkpoint' + dataset: + $ref: '#/components/schemas/TrainEvalDataset' + job_uuid: + type: string + metrics: + items: + enum: + - em + - f1 + type: string + type: array + sampling_params: + $ref: '#/components/schemas/SamplingParams' + required: + - job_uuid + - dataset + - checkpoint + - sampling_params + - metrics + title: Request to evaluate question answering. + type: object + EvaluateSummarizationRequest: + additionalProperties: false + properties: + checkpoint: + $ref: '#/components/schemas/Checkpoint' + dataset: + $ref: '#/components/schemas/TrainEvalDataset' + job_uuid: + type: string + metrics: + items: + enum: + - rouge + - bleu + type: string + type: array + sampling_params: + $ref: '#/components/schemas/SamplingParams' + required: + - job_uuid + - dataset + - checkpoint + - sampling_params + - metrics + title: Request to evaluate summarization. + type: object + EvaluateTextGenerationRequest: + additionalProperties: false + properties: + checkpoint: + $ref: '#/components/schemas/Checkpoint' + dataset: + $ref: '#/components/schemas/TrainEvalDataset' + job_uuid: + type: string + metrics: + items: + enum: + - perplexity + - rouge + - bleu + type: string + type: array + sampling_params: + $ref: '#/components/schemas/SamplingParams' + required: + - job_uuid + - dataset + - checkpoint + - sampling_params + - metrics + title: Request to evaluate text generation. + type: object + EvaluationJob: + additionalProperties: false + properties: + job_uuid: + type: string + required: + - job_uuid + type: object + EvaluationJobArtifactsResponse: + additionalProperties: false + properties: + job_uuid: + type: string + required: + - job_uuid + title: Artifacts of a evaluation job. + type: object + EvaluationJobLogStream: + additionalProperties: false + properties: + job_uuid: + type: string + required: + - job_uuid + type: object + EvaluationJobStatusResponse: + additionalProperties: false + properties: + job_uuid: + type: string + required: + - job_uuid + type: object + Experiment: + additionalProperties: false + properties: + created_at: + format: date-time + type: string + id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + name: + type: string + status: + $ref: '#/components/schemas/ExperimentStatus' + updated_at: + format: date-time + type: string + required: + - id + - name + - status + - created_at + - updated_at + - metadata + type: object + ExperimentStatus: + enum: + - not_started + - running + - completed + - failed + type: string + FinetuningAlgorithm: + enum: + - full + - lora + - qlora + - dora + type: string + Fp8QuantizationConfig: + additionalProperties: false + properties: + type: + const: fp8 + type: string + required: + - type + type: object + InferenceStep: + additionalProperties: false + properties: + completed_at: + format: date-time + type: string + model_response: + $ref: '#/components/schemas/CompletionMessage' + started_at: + format: date-time + type: string + step_id: + type: string + step_type: + const: inference + type: string + turn_id: + type: string + required: + - turn_id + - step_id + - step_type + - model_response + type: object + Log: + additionalProperties: false + properties: + additional_info: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + level: + type: string + message: + type: string + timestamp: + format: date-time + type: string + required: + - message + - level + - timestamp + - additional_info + type: object + LogMessagesRequest: + additionalProperties: false + properties: + logs: + items: + $ref: '#/components/schemas/Log' + type: array + run_id: + type: string + required: + - logs + type: object + LogMetricsRequest: + additionalProperties: false + properties: + metrics: + items: + $ref: '#/components/schemas/Metric' + type: array + run_id: + type: string + required: + - run_id + - metrics + type: object + LogSearchRequest: + additionalProperties: false + properties: + filters: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + query: + type: string + required: + - query + type: object + LoraFinetuningConfig: + additionalProperties: false + properties: + alpha: + type: integer + apply_lora_to_mlp: + type: boolean + apply_lora_to_output: + type: boolean + lora_attn_modules: + items: + type: string + type: array + rank: + type: integer + required: + - lora_attn_modules + - apply_lora_to_mlp + - apply_lora_to_output + - rank + - alpha + type: object + MemoryBank: + additionalProperties: false + properties: + memory_bank_id: + type: string + memory_bank_name: + type: string + required: + - memory_bank_id + - memory_bank_name + type: object + MemoryBankDocument: + additionalProperties: false + properties: + content: + contentEncoding: base64 + type: string + document_id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + mime_type: + type: string + required: + - document_id + - content + - metadata + - mime_type + type: object + MemoryRetrievalStep: + additionalProperties: false + properties: + completed_at: + format: date-time + type: string + documents: + items: + $ref: '#/components/schemas/MemoryBankDocument' + type: array + memory_bank_ids: + items: + type: string + type: array + scores: + items: + type: number + type: array + started_at: + format: date-time + type: string + step_id: + type: string + step_type: + const: memory_retrieval + type: string + turn_id: + type: string + required: + - turn_id + - step_id + - step_type + - memory_bank_ids + - documents + - scores + type: object + Metric: + additionalProperties: false + properties: + name: + type: string + run_id: + type: string + timestamp: + format: date-time + type: string + value: + oneOf: + - type: number + - type: integer + - type: string + - type: boolean + required: + - name + - value + - timestamp + - run_id + type: object + OnViolationAction: + enum: + - 0 + - 1 + - 2 + type: integer + OptimizerConfig: + additionalProperties: false + properties: + lr: + type: number + lr_min: + type: number + optimizer_type: + enum: + - adam + - adamw + - sgd + type: string + weight_decay: + type: number + required: + - optimizer_type + - lr + - lr_min + - weight_decay + type: object + PostTrainingJob: + additionalProperties: false + properties: + job_uuid: + type: string + required: + - job_uuid + type: object + PostTrainingJobArtifactsResponse: + additionalProperties: false + properties: + checkpoints: + items: + $ref: '#/components/schemas/Checkpoint' + type: array + job_uuid: + type: string + required: + - job_uuid + - checkpoints + title: Artifacts of a finetuning job. + type: object + PostTrainingJobLogStream: + additionalProperties: false + properties: + job_uuid: + type: string + log_lines: + items: + type: string + type: array + required: + - job_uuid + - log_lines + title: Stream of logs from a finetuning job. + type: object + PostTrainingJobStatus: + enum: + - running + - completed + - failed + - scheduled + type: string + PostTrainingJobStatusResponse: + additionalProperties: false + properties: + checkpoints: + items: + $ref: '#/components/schemas/Checkpoint' + type: array + completed_at: + format: date-time + type: string + job_uuid: + type: string + resources_allocated: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + scheduled_at: + format: date-time + type: string + started_at: + format: date-time + type: string + status: + $ref: '#/components/schemas/PostTrainingJobStatus' + required: + - job_uuid + - status + - checkpoints + title: Status of a finetuning job. + type: object + PostTrainingRLHFRequest: + additionalProperties: false + properties: + algorithm: + $ref: '#/components/schemas/RLHFAlgorithm' + algorithm_config: + $ref: '#/components/schemas/DPOAlignmentConfig' + dataset: + $ref: '#/components/schemas/TrainEvalDataset' + finetuned_model: + $ref: '#/components/schemas/URL' + hyperparam_search_config: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + job_uuid: + type: string + logger_config: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + optimizer_config: + $ref: '#/components/schemas/OptimizerConfig' + training_config: + $ref: '#/components/schemas/TrainingConfig' + validation_dataset: + $ref: '#/components/schemas/TrainEvalDataset' + required: + - job_uuid + - finetuned_model + - dataset + - validation_dataset + - algorithm + - algorithm_config + - optimizer_config + - training_config + - hyperparam_search_config + - logger_config + title: Request to finetune a model. + type: object + PostTrainingSFTRequest: + additionalProperties: false + properties: + algorithm: + $ref: '#/components/schemas/FinetuningAlgorithm' + algorithm_config: + oneOf: + - $ref: '#/components/schemas/LoraFinetuningConfig' + - $ref: '#/components/schemas/QLoraFinetuningConfig' + - $ref: '#/components/schemas/DoraFinetuningConfig' + dataset: + $ref: '#/components/schemas/TrainEvalDataset' + hyperparam_search_config: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + job_uuid: + type: string + logger_config: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + model: + type: string + optimizer_config: + $ref: '#/components/schemas/OptimizerConfig' + training_config: + $ref: '#/components/schemas/TrainingConfig' + validation_dataset: + $ref: '#/components/schemas/TrainEvalDataset' + required: + - job_uuid + - model + - dataset + - validation_dataset + - algorithm + - algorithm_config + - optimizer_config + - training_config + - hyperparam_search_config + - logger_config + title: Request to finetune a model. + type: object + QLoraFinetuningConfig: + additionalProperties: false + properties: + alpha: + type: integer + apply_lora_to_mlp: + type: boolean + apply_lora_to_output: + type: boolean + lora_attn_modules: + items: + type: string + type: array + rank: + type: integer + required: + - lora_attn_modules + - apply_lora_to_mlp + - apply_lora_to_output + - rank + - alpha + type: object + RLHFAlgorithm: + enum: + - dpo + type: string + RestAPIExecutionConfig: + additionalProperties: false + properties: + body: + additionalProperties: + type: string + type: object + headers: + additionalProperties: + type: string + type: object + method: + $ref: '#/components/schemas/RestAPIMethod' + params: + additionalProperties: + type: string + type: object + url: + $ref: '#/components/schemas/URL' + required: + - url + - method + type: object + RestAPIMethod: + enum: + - GET + - POST + - PUT + - DELETE + type: string + RewardScoringRequest: + additionalProperties: false + properties: + dialog_generations: + items: + $ref: '#/components/schemas/DialogGenerations' + type: array + model: + type: string + required: + - dialog_generations + - model + title: Request to score a reward function. A list of prompts and a list of responses + per prompt. + type: object + RewardScoringResponse: + additionalProperties: false + properties: + scored_generations: + items: + $ref: '#/components/schemas/ScoredDialogGenerations' + type: array + required: + - scored_generations + title: Response from the reward scoring. Batch of (prompt, response, score) + tuples that pass the threshold. + type: object + Run: + additionalProperties: false + properties: + ended_at: + format: date-time + type: string + experiment_id: + type: string + id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + started_at: + format: date-time + type: string + status: + type: string + required: + - id + - experiment_id + - status + - started_at + - metadata + type: object + SamplingParams: + additionalProperties: false + properties: + max_tokens: + type: integer + repetition_penalty: + type: number + strategy: + $ref: '#/components/schemas/SamplingStrategy' + temperature: + type: number + top_k: + type: integer + top_p: + type: number + required: + - strategy + type: object + SamplingStrategy: + enum: + - greedy + - top_p + - top_k + type: string + ScoredDialogGenerations: + additionalProperties: false + properties: + dialog: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + scored_generations: + items: + $ref: '#/components/schemas/ScoredMessage' + type: array + required: + - dialog + - scored_generations + type: object + ScoredMessage: + additionalProperties: false + properties: + message: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + score: + type: number + required: + - message + - score + type: object + Session: + additionalProperties: false + properties: + session_id: + type: string + session_name: + type: string + started_at: + format: date-time + type: string + turns: + items: + $ref: '#/components/schemas/Turn' + type: array + required: + - session_id + - session_name + - turns + - started_at + title: A single session of an interaction with an Agentic System. + type: object + ShieldCallStep: + additionalProperties: false + properties: + completed_at: + format: date-time + type: string + response: + $ref: '#/components/schemas/ShieldResponse' + started_at: + format: date-time + type: string + step_id: + type: string + step_type: + const: shield_call + type: string + turn_id: + type: string + required: + - turn_id + - step_id + - step_type + - response + type: object + ShieldDefinition: + additionalProperties: false + properties: + description: + type: string + execution_config: + $ref: '#/components/schemas/RestAPIExecutionConfig' + on_violation_action: + $ref: '#/components/schemas/OnViolationAction' + parameters: + additionalProperties: + $ref: '#/components/schemas/ToolParamDefinition' + type: object + shield_type: + oneOf: + - $ref: '#/components/schemas/BuiltinShield' + - type: string + required: + - shield_type + - on_violation_action + type: object + ShieldResponse: + additionalProperties: false + properties: + is_violation: + type: boolean + shield_type: + oneOf: + - $ref: '#/components/schemas/BuiltinShield' + - type: string + violation_return_message: + type: string + violation_type: + type: string + required: + - shield_type + - is_violation + type: object + StopReason: + enum: + - end_of_turn + - end_of_message + - out_of_tokens + type: string + SyntheticDataGenerationRequest: + additionalProperties: false + properties: + dialogs: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/SystemMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + - $ref: '#/components/schemas/CompletionMessage' + type: array + filtering_function: + enum: + - none + - random + - top_k + - top_p + - top_k_top_p + - sigmoid + title: The type of filtering function. + type: string + model: + type: string + required: + - dialogs + - filtering_function + title: Request to generate synthetic data. A small batch of prompts and a filtering + function + type: object + SyntheticDataGenerationResponse: + additionalProperties: false + properties: + statistics: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + synthetic_data: + items: + $ref: '#/components/schemas/ScoredDialogGenerations' + type: array + required: + - synthetic_data + title: Response from the synthetic data generation. Batch of (prompt, response, + score) tuples that pass the threshold. + type: object + SystemMessage: + additionalProperties: false + properties: + content: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + role: + const: system + type: string + required: + - role + - content + type: object + TokenLogProbs: + additionalProperties: false + properties: + logprobs_by_token: + additionalProperties: + type: number + type: object + required: + - logprobs_by_token + type: object + ToolCall: + additionalProperties: false + properties: + arguments: + additionalProperties: + oneOf: + - type: string + - type: integer + - type: number + - type: boolean + - type: 'null' + - items: + oneOf: + - type: string + - type: integer + - type: number + - type: boolean + - type: 'null' + type: array + - additionalProperties: + oneOf: + - type: string + - type: integer + - type: number + - type: boolean + - type: 'null' + type: object + type: object + call_id: + type: string + tool_name: + oneOf: + - $ref: '#/components/schemas/BuiltinTool' + - type: string + required: + - call_id + - tool_name + - arguments + type: object + ToolCallDelta: + additionalProperties: false + properties: + content: + oneOf: + - type: string + - $ref: '#/components/schemas/ToolCall' + parse_status: + $ref: '#/components/schemas/ToolCallParseStatus' + required: + - content + - parse_status + type: object + ToolCallParseStatus: + enum: + - started + - in_progress + - failure + - success + type: string + ToolDefinition: + additionalProperties: false + properties: + description: + type: string + parameters: + additionalProperties: + $ref: '#/components/schemas/ToolParamDefinition' + type: object + tool_name: + oneOf: + - $ref: '#/components/schemas/BuiltinTool' + - type: string + required: + - tool_name + type: object + ToolExecutionStep: + additionalProperties: false + properties: + completed_at: + format: date-time + type: string + started_at: + format: date-time + type: string + step_id: + type: string + step_type: + const: tool_execution + type: string + tool_calls: + items: + $ref: '#/components/schemas/ToolCall' + type: array + tool_responses: + items: + $ref: '#/components/schemas/ToolResponse' + type: array + turn_id: + type: string + required: + - turn_id + - step_id + - step_type + - tool_calls + - tool_responses + type: object + ToolParamDefinition: + additionalProperties: false + properties: + description: + type: string + param_type: + type: string + required: + type: boolean + required: + - param_type + type: object + ToolPromptFormat: + description: "`json` --\n Refers to the json format for calling tools.\n\ + \ The json format takes the form like\n {\n \"type\": \"function\"\ + ,\n \"function\" : {\n \"name\": \"function_name\",\n \ + \ \"description\": \"function_description\",\n \"parameters\"\ + : {...}\n }\n }\n\n`function_tag` --\n This is an example of\ + \ how you could define\n your own user defined format for making tool calls.\n\ + \ The function_tag format looks like this,\n (parameters)\n\ + \nThe detailed prompts for each of these formats are defined in `system_prompt.py`" + enum: + - json + - function_tag + title: This Enum refers to the prompt format for calling zero shot tools + type: string + ToolResponse: + additionalProperties: false + properties: + call_id: + type: string + content: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + tool_name: + oneOf: + - $ref: '#/components/schemas/BuiltinTool' + - type: string + required: + - call_id + - tool_name + - content + type: object + ToolResponseMessage: + additionalProperties: false + properties: + call_id: + type: string + content: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + role: + const: ipython + type: string + tool_name: + oneOf: + - $ref: '#/components/schemas/BuiltinTool' + - type: string + required: + - role + - call_id + - tool_name + - content + type: object + TrainEvalDataset: + additionalProperties: false + properties: + columns: + additionalProperties: + $ref: '#/components/schemas/TrainEvalDatasetColumnType' + type: object + content_url: + $ref: '#/components/schemas/URL' + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + required: + - columns + - content_url + title: Dataset to be used for training or evaluating language models. + type: object + TrainEvalDatasetColumnType: + enum: + - dialog + - text + - media + - number + - json + type: string + TrainingConfig: + additionalProperties: false + properties: + batch_size: + type: integer + enable_activation_checkpointing: + type: boolean + fsdp_cpu_offload: + type: boolean + memory_efficient_fsdp_wrap: + type: boolean + n_epochs: + type: integer + n_iters: + type: integer + shuffle: + type: boolean + required: + - n_epochs + - batch_size + - shuffle + - n_iters + - enable_activation_checkpointing + - memory_efficient_fsdp_wrap + - fsdp_cpu_offload + type: object + Turn: + additionalProperties: false + properties: + completed_at: + format: date-time + type: string + input_messages: + items: + oneOf: + - $ref: '#/components/schemas/UserMessage' + - $ref: '#/components/schemas/ToolResponseMessage' + type: array + output_message: + $ref: '#/components/schemas/CompletionMessage' + session_id: + type: string + started_at: + format: date-time + type: string + steps: + items: + oneOf: + - $ref: '#/components/schemas/InferenceStep' + - $ref: '#/components/schemas/ToolExecutionStep' + - $ref: '#/components/schemas/ShieldCallStep' + - $ref: '#/components/schemas/MemoryRetrievalStep' + type: array + turn_id: + type: string + required: + - turn_id + - session_id + - input_messages + - steps + - output_message + - started_at + title: A single turn in an interaction with an Agentic System. + type: object + URL: + format: uri + pattern: ^(https?://|file://|data:) + type: string + UpdateExperimentRequest: + additionalProperties: false + properties: + experiment_id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + status: + $ref: '#/components/schemas/ExperimentStatus' + required: + - experiment_id + type: object + UpdateRunRequest: + additionalProperties: false + properties: + ended_at: + format: date-time + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + run_id: + type: string + status: + type: string + required: + - run_id + type: object + UploadArtifactRequest: + additionalProperties: false + properties: + artifact_type: + type: string + content: + contentEncoding: base64 + type: string + experiment_id: + type: string + metadata: + additionalProperties: + oneOf: + - type: 'null' + - type: boolean + - type: number + - type: string + - type: array + - type: object + type: object + name: + type: string + required: + - experiment_id + - name + - artifact_type + - content + type: object + UserMessage: + additionalProperties: false + properties: + content: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + - items: + oneOf: + - type: string + - $ref: '#/components/schemas/Attachment' + type: array + role: + const: user + type: string + required: + - role + - content + type: object +info: + description: "This is the specification of the llama stack that provides\n \ + \ a set of endpoints and their corresponding interfaces that are tailored\ + \ to\n best leverage Llama Models. The specification is still in\ + \ draft and subject to change.\n Generated at 2024-08-20 19:00:39.110138" + title: '[DRAFT] Llama Stack Specification' + version: 0.0.1 +jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema +openapi: 3.1.0 +paths: + /agentic_system/create: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemCreateRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemCreateResponse' + description: OK + tags: + - AgenticSystem + /agentic_system/delete: + delete: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + responses: + '200': + description: OK + tags: + - AgenticSystem + /agentic_system/memory_bank/attach: + post: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + - in: query + name: session_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + type: string + type: array + required: true + responses: + '200': + description: OK + tags: + - AgenticSystem + /agentic_system/memory_bank/detach: + post: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + - in: query + name: session_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + type: string + type: array + required: true + responses: + '200': + description: OK + tags: + - AgenticSystem + /agentic_system/session/create: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemSessionCreateRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemSessionCreateResponse' + description: OK + tags: + - AgenticSystem + /agentic_system/session/delete: + delete: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + - in: query + name: session_id + required: true + schema: + type: string + responses: + '200': + description: OK + tags: + - AgenticSystem + /agentic_system/session/get: + post: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + - in: query + name: session_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + oneOf: + - items: + type: string + type: array + - type: 'null' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Session' + description: OK + tags: + - AgenticSystem + /agentic_system/step/get: + get: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + - in: query + name: turn_id + required: true + schema: + type: string + - in: query + name: step_id + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemStepResponse' + description: OK + tags: + - AgenticSystem + /agentic_system/turn/create: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemTurnCreateRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AgenticSystemTurnResponseStreamChunk' + description: OK + tags: + - AgenticSystem + /agentic_system/turn/get: + get: + parameters: + - in: query + name: agent_id + required: true + schema: + type: string + - in: query + name: turn_id + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Turn' + description: OK + tags: + - AgenticSystem + /artifacts/get: + get: + parameters: + - in: query + name: artifact_id + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Artifact' + description: OK + tags: + - Observability + /datasets/create: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateDatasetRequest' + required: true + responses: + '200': + description: OK + tags: + - Datasets + /datasets/delete: + delete: + parameters: + - in: query + name: dataset_uuid + required: true + schema: + type: string + responses: + '200': + description: OK + tags: + - Datasets + /datasets/get: + get: + parameters: + - in: query + name: dataset_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TrainEvalDataset' + description: OK + tags: + - Datasets + /evaluate/job/artifacts: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluationJobArtifactsResponse' + description: OK + tags: + - Evaluations + /evaluate/job/cancel: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + description: OK + tags: + - Evaluations + /evaluate/job/logs: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluationJobLogStream' + description: OK + tags: + - Evaluations + /evaluate/job/status: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluationJobStatusResponse' + description: OK + tags: + - Evaluations + /evaluate/jobs: + get: + parameters: [] + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/EvaluationJob' + description: OK + tags: + - Evaluations + /evaluate/question_answering/: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluateQuestionAnsweringRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluationJob' + description: OK + tags: + - Evaluations + /evaluate/summarization/: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluateSummarizationRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluationJob' + description: OK + tags: + - Evaluations + /evaluate/text_generation/: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluateTextGenerationRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EvaluationJob' + description: OK + tags: + - Evaluations + /experiments/artifacts/get: + get: + parameters: + - in: query + name: experiment_id + required: true + schema: + type: string + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/Artifact' + description: OK + tags: + - Observability + /experiments/artifacts/upload: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UploadArtifactRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Artifact' + description: OK + tags: + - Observability + /experiments/create: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateExperimentRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Experiment' + description: OK + tags: + - Observability + /experiments/create_run: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateRunRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Run' + description: OK + tags: + - Observability + /experiments/get: + get: + parameters: + - in: query + name: experiment_id + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Experiment' + description: OK + tags: + - Observability + /experiments/list: + get: + parameters: [] + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/Experiment' + description: OK + tags: + - Observability + /experiments/update: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateExperimentRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Experiment' + description: OK + tags: + - Observability + /inference/batch_chat_completion: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BatchChatCompletionRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BatchChatCompletionResponse' + description: OK + tags: + - Inference + /inference/batch_completion: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BatchCompletionRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BatchCompletionResponse' + description: OK + tags: + - Inference + /inference/chat_completion: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ChatCompletionRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ChatCompletionResponseStreamChunk' + description: SSE-stream of these events. + tags: + - Inference + /inference/completion: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CompletionRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CompletionResponseStreamChunk' + description: streamed completion response. + tags: + - Inference + /logging/get_logs: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LogSearchRequest' + required: true + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/Log' + description: OK + tags: + - Observability + /logging/log_messages: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LogMessagesRequest' + required: true + responses: + '200': + description: OK + tags: + - Observability + /memory_bank/delete: + post: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + type: string + type: array + required: true + responses: + '200': + content: + application/jsonl: + schema: + type: string + description: OK + tags: + - MemoryBanks + /memory_bank/get: + post: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + type: string + type: array + required: true + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/MemoryBankDocument' + description: OK + tags: + - MemoryBanks + /memory_bank/insert: + post: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/MemoryBankDocument' + type: array + required: true + responses: + '200': + description: OK + tags: + - MemoryBanks + /memory_bank/update: + post: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/MemoryBankDocument' + type: array + required: true + responses: + '200': + description: OK + tags: + - MemoryBanks + /memory_banks/create: + post: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + - in: query + name: bank_name + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + $ref: '#/components/schemas/MemoryBankDocument' + type: array + required: true + responses: + '200': + description: OK + tags: + - MemoryBanks + /memory_banks/drop: + delete: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: string + description: OK + tags: + - MemoryBanks + /memory_banks/get: + get: + parameters: + - in: query + name: bank_id + required: true + schema: + type: string + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/MemoryBank' + description: OK + tags: + - MemoryBanks + /memory_banks/list: + get: + parameters: [] + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/MemoryBank' + description: OK + tags: + - MemoryBanks + /post_training/job/artifacts: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingJobArtifactsResponse' + description: OK + tags: + - PostTraining + /post_training/job/cancel: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + description: OK + tags: + - PostTraining + /post_training/job/logs: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingJobLogStream' + description: OK + tags: + - PostTraining + /post_training/job/status: + get: + parameters: + - in: query + name: job_uuid + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingJobStatusResponse' + description: OK + tags: + - PostTraining + /post_training/jobs: + get: + parameters: [] + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/PostTrainingJob' + description: OK + tags: + - PostTraining + /post_training/preference_optimize: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingRLHFRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingJob' + description: OK + tags: + - PostTraining + /post_training/supervised_fine_tune: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingSFTRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PostTrainingJob' + description: OK + tags: + - PostTraining + /reward_scoring/score: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RewardScoringRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RewardScoringResponse' + description: OK + tags: + - RewardScoring + /runs/log_metrics: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LogMetricsRequest' + required: true + responses: + '200': + description: OK + tags: + - Observability + /runs/metrics: + get: + parameters: + - in: query + name: run_id + required: true + schema: + type: string + responses: + '200': + content: + application/jsonl: + schema: + $ref: '#/components/schemas/Metric' + description: OK + tags: + - Observability + /runs/update: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateRunRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Run' + description: OK + tags: + - Observability + /synthetic_data_generation/generate: + post: + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SyntheticDataGenerationRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SyntheticDataGenerationResponse' + description: OK + tags: + - SyntheticDataGeneration +security: +- Default: [] +servers: +- url: http://any-hosted-llama-stack.com +tags: +- name: RewardScoring +- name: AgenticSystem +- name: SyntheticDataGeneration +- name: Inference +- name: Datasets +- name: Observability +- name: PostTraining +- name: MemoryBanks +- name: Evaluations +- description: + name: Attachment +- description: + name: BatchChatCompletionRequest +- description: + name: Bf16QuantizationConfig +- description: + name: BuiltinTool +- description: + name: CompletionMessage +- description: + name: Fp8QuantizationConfig +- description: + name: SamplingParams +- description: + name: SamplingStrategy +- description: + name: StopReason +- description: + name: SystemMessage +- description: + name: ToolCall +- description: + name: ToolDefinition +- description: + name: ToolParamDefinition +- description: + name: ToolResponseMessage +- description: + name: URL +- description: + name: UserMessage +- description: + name: BatchChatCompletionResponse +- description: + name: BatchCompletionRequest +- description: + name: BatchCompletionResponse +- description: + name: ChatCompletionRequest +- description: 'Chat completion response event. + + + ' + name: ChatCompletionResponseEvent +- description: + name: ChatCompletionResponseEventType +- description: 'SSE-stream of these events. + + + ' + name: ChatCompletionResponseStreamChunk +- description: + name: TokenLogProbs +- description: + name: ToolCallDelta +- description: + name: ToolCallParseStatus +- description: + name: CompletionRequest +- description: 'streamed completion response. + + + ' + name: CompletionResponseStreamChunk +- description: + name: AgenticSystemCreateRequest +- description: + name: AgenticSystemInstanceConfig +- description: + name: AgenticSystemToolDefinition +- description: + name: BuiltinShield +- description: + name: OnViolationAction +- description: + name: RestAPIExecutionConfig +- description: + name: RestAPIMethod +- description: + name: ShieldDefinition +- description: "This Enum refers to the prompt format for calling zero shot tools\n\ + \n`json` --\n Refers to the json format for calling tools.\n The json format\ + \ takes the form like\n {\n \"type\": \"function\",\n \"function\"\ + \ : {\n \"name\": \"function_name\",\n \"description\":\ + \ \"function_description\",\n \"parameters\": {...}\n }\n \ + \ }\n\n`function_tag` --\n This is an example of how you could define\n \ + \ your own user defined format for making tool calls.\n The function_tag format\ + \ looks like this,\n (parameters)\n\nThe\ + \ detailed prompts for each of these formats are defined in `system_prompt.py`\n\ + \n" + name: ToolPromptFormat +- description: + name: AgenticSystemCreateResponse +- description: + name: AgenticSystemSessionCreateRequest +- description: + name: AgenticSystemSessionCreateResponse +- description: + name: AgenticSystemTurnCreateRequest +- description: 'Server side event (SSE) stream of these events + + + ' + name: AgenticSystemTurnResponseStreamChunk +- description: 'Request to create a dataset. + + + ' + name: CreateDatasetRequest +- description: 'Dataset to be used for training or evaluating language models. + + + ' + name: TrainEvalDataset +- description: + name: TrainEvalDatasetColumnType +- description: + name: CreateExperimentRequest +- description: + name: Experiment +- description: + name: ExperimentStatus +- description: + name: MemoryBankDocument +- description: + name: CreateRunRequest +- description: + name: Run +- description: 'Checkpoint created during training runs + + + ' + name: Checkpoint +- description: 'Request to evaluate question answering. + + + ' + name: EvaluateQuestionAnsweringRequest +- description: + name: EvaluationJob +- description: 'Request to evaluate summarization. + + + ' + name: EvaluateSummarizationRequest +- description: 'Request to evaluate text generation. + + + ' + name: EvaluateTextGenerationRequest +- description: + name: InferenceStep +- description: + name: MemoryRetrievalStep +- description: 'A single session of an interaction with an Agentic System. + + + ' + name: Session +- description: + name: ShieldCallStep +- description: + name: ShieldResponse +- description: + name: ToolExecutionStep +- description: + name: ToolResponse +- description: 'A single turn in an interaction with an Agentic System. + + + ' + name: Turn +- description: + name: AgenticSystemStepResponse +- description: + name: Artifact +- description: + name: ArtifactType +- description: 'Artifacts of a evaluation job. + + + ' + name: EvaluationJobArtifactsResponse +- description: + name: EvaluationJobLogStream +- description: + name: EvaluationJobStatusResponse +- description: + name: LogSearchRequest +- description: + name: Log +- description: + name: MemoryBank +- description: + name: Metric +- description: 'Artifacts of a finetuning job. + + + ' + name: PostTrainingJobArtifactsResponse +- description: 'Stream of logs from a finetuning job. + + + ' + name: PostTrainingJobLogStream +- description: + name: PostTrainingJobStatus +- description: 'Status of a finetuning job. + + + ' + name: PostTrainingJobStatusResponse +- description: + name: PostTrainingJob +- description: + name: LogMessagesRequest +- description: + name: LogMetricsRequest +- description: + name: DPOAlignmentConfig +- description: + name: OptimizerConfig +- description: 'Request to finetune a model. + + + ' + name: PostTrainingRLHFRequest +- description: + name: RLHFAlgorithm +- description: + name: TrainingConfig +- description: + name: DialogGenerations +- description: 'Request to score a reward function. A list of prompts and a list of + responses per prompt. + + + ' + name: RewardScoringRequest +- description: 'Response from the reward scoring. Batch of (prompt, response, score) + tuples that pass the threshold. + + + ' + name: RewardScoringResponse +- description: + name: ScoredDialogGenerations +- description: + name: ScoredMessage +- description: + name: DoraFinetuningConfig +- description: + name: FinetuningAlgorithm +- description: + name: LoraFinetuningConfig +- description: 'Request to finetune a model. + + + ' + name: PostTrainingSFTRequest +- description: + name: QLoraFinetuningConfig +- description: 'Request to generate synthetic data. A small batch of prompts and a + filtering function + + + ' + name: SyntheticDataGenerationRequest +- description: 'Response from the synthetic data generation. Batch of (prompt, response, + score) tuples that pass the threshold. + + + ' + name: SyntheticDataGenerationResponse +- description: + name: UpdateExperimentRequest +- description: + name: UpdateRunRequest +- description: + name: UploadArtifactRequest +x-tagGroups: +- name: Operations + tags: + - AgenticSystem + - Datasets + - Evaluations + - Inference + - MemoryBanks + - Observability + - PostTraining + - RewardScoring + - SyntheticDataGeneration +- name: Types + tags: + - AgenticSystemCreateRequest + - AgenticSystemCreateResponse + - AgenticSystemInstanceConfig + - AgenticSystemSessionCreateRequest + - AgenticSystemSessionCreateResponse + - AgenticSystemStepResponse + - AgenticSystemToolDefinition + - AgenticSystemTurnCreateRequest + - AgenticSystemTurnResponseStreamChunk + - Artifact + - ArtifactType + - Attachment + - BatchChatCompletionRequest + - BatchChatCompletionResponse + - BatchCompletionRequest + - BatchCompletionResponse + - Bf16QuantizationConfig + - BuiltinShield + - BuiltinTool + - ChatCompletionRequest + - ChatCompletionResponseEvent + - ChatCompletionResponseEventType + - ChatCompletionResponseStreamChunk + - Checkpoint + - CompletionMessage + - CompletionRequest + - CompletionResponseStreamChunk + - CreateDatasetRequest + - CreateExperimentRequest + - CreateRunRequest + - DPOAlignmentConfig + - DialogGenerations + - DoraFinetuningConfig + - EvaluateQuestionAnsweringRequest + - EvaluateSummarizationRequest + - EvaluateTextGenerationRequest + - EvaluationJob + - EvaluationJobArtifactsResponse + - EvaluationJobLogStream + - EvaluationJobStatusResponse + - Experiment + - ExperimentStatus + - FinetuningAlgorithm + - Fp8QuantizationConfig + - InferenceStep + - Log + - LogMessagesRequest + - LogMetricsRequest + - LogSearchRequest + - LoraFinetuningConfig + - MemoryBank + - MemoryBankDocument + - MemoryRetrievalStep + - Metric + - OnViolationAction + - OptimizerConfig + - PostTrainingJob + - PostTrainingJobArtifactsResponse + - PostTrainingJobLogStream + - PostTrainingJobStatus + - PostTrainingJobStatusResponse + - PostTrainingRLHFRequest + - PostTrainingSFTRequest + - QLoraFinetuningConfig + - RLHFAlgorithm + - RestAPIExecutionConfig + - RestAPIMethod + - RewardScoringRequest + - RewardScoringResponse + - Run + - SamplingParams + - SamplingStrategy + - ScoredDialogGenerations + - ScoredMessage + - Session + - ShieldCallStep + - ShieldDefinition + - ShieldResponse + - StopReason + - SyntheticDataGenerationRequest + - SyntheticDataGenerationResponse + - SystemMessage + - TokenLogProbs + - ToolCall + - ToolCallDelta + - ToolCallParseStatus + - ToolDefinition + - ToolExecutionStep + - ToolParamDefinition + - ToolPromptFormat + - ToolResponse + - ToolResponseMessage + - TrainEvalDataset + - TrainEvalDatasetColumnType + - TrainingConfig + - Turn + - URL + - UpdateExperimentRequest + - UpdateRunRequest + - UploadArtifactRequest + - UserMessage diff --git a/rfcs/RFC-0001-llama-stack-assets/llama-stack.png b/rfcs/RFC-0001-llama-stack-assets/llama-stack.png new file mode 100644 index 0000000000000000000000000000000000000000..e5a64711450f327d956e4bf39f624804528f8622 GIT binary patch literal 72643 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 YPcC6dbDH`nlmQ4lUHx3vIVCg!03cp)vj6}9 literal 0 HcmV?d00001 diff --git a/rfcs/RFC-0001-llama-stack-assets/model-lifecycle.png b/rfcs/RFC-0001-llama-stack-assets/model-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..fe74ae459cf60e06c94bd2c8a30e6fc6ad99ff82 GIT binary patch literal 17824 zcmbunc{En-`!>FB5+Q^V5gJSxBXdZGkTE5*WX_n((=Ce1OeAB5kU4XvTasj+G7k}% z=Xre3-RJXrf9w0lyVkqb`>gfQbGPrkuYFzTb)Lt09LM#%Qd5yXO-x6OAjoNjJ2Dyw zf(L)ZTqZgRzhp8ij^Wn{M`;C3BKXIX$RrR!m=Fb-Tbi!%3nOlNnwv+Bt9>m6uP;TU z_+DD7u(RN{wBoRxRbDr@j26n>h~{$c)wTRsI$IJqz=a?4Q%~ovvJHQqULm!{@LT0G z>bJH`&rk2~KaQs=e}?hJZ~43Hx}rvA-d0817P}t1yqma8<4++?#QcBx-CsqULAP8_%v_hQlW_uFw`#C!Uh})TS*Xp@C?6I$9> z`#UfU-XBRNS7=F3c6D{_tTr-YoblJO%bUtq6+76BzI0kxGg4E_lvwquDYhM7UF^xa zM=$d94`l(RE7hG&kqC;jgH%|ZYWEVwyLUBHo|&4OW)&3hZuUP8WjDGop0hq?I85s@ z{^Q##s{1lB{@3GL-ItBuzVEfVf9ljJtJ$t};ve`If9)>w$h^2wXjtn#H(2t-ow1M1 za^SNmabTARD@B7D9=F%=;kNs-BH8TM7bHI$8|5*VH%HI-XIcy*9M`TXEl>7;;L<6+ zgGrjL;t8A>D0N=csdixwaGv^k_C>CplufnENoI}+L+`^)t?E$24^e9y8=BbsQ89nE z2wa|i3iP|{70 z(oxzI9obqu*yDO<1-U3bc7!9*R#klU1WP16&(y69l?23nKH)ZX)8Y28V<=oaJ~8oC z@@SRZJUM+-n?9TxIjg$(^7Mtdgj;%lr>9S zVANL6Pj&n3I(W4Zh=g#QOYLOy`Mfro+zHLF0%%j2c112|of)3Vzv3X&`8Dk=-Fi;MZ4-!hgTaT8$sr<*+&- zJL+@nb&m6)R50BQ*Uet7SYd}t_p={xg)f?$n@2`Q-rk(+B{_W8(V-@2Gw82DoKD@= z)^>t`K>c0p>F(}szVoE6uCBuh3)hG8D4d`C%J~he|7U8-vKb=motO*vwFf!LTKNXW zwj*C24%IxJBEIqDS24K)mrVE_5~-`yG&BK8NsLQNOYx#kuM@;vK6~vuKY#wb;34PL zHTp`IWwYs)SXuX$-Sxk2^SNa+qt#-tPN|RTUp`wNO@L32+Z(y{zeK4@?534F*ge@@ zo8r{}Qv9v#n*WF|K4D-`P@3c4wr4XPzGMud9VJh+;u8|G45~%p9U2Dn2CTm~HU?~L zY*4Cj(!VH1G^OF0SY!B+(Ys3V(X8bcVe3~MEjSFc_z43@lUX}RmZG4p|| zy}9}E-?oG+tgPLi?q7R<(uGfQ#Jcb^}W4sH#VMaEezCSG5EqxbJX12+*epw zC~0Y%Zf+0XjuW&gCf(m&{tJ6uz`8#ygh4F2mE_V-0!vJ$$>*Y?Q)Faj3;l%z(OTIL zPN!3&v%tw2v_0yfx<8P3(_?3A$PP2pm(N)8q|dD3_1W{ma&n;;TN@dDf24_W9T=Q%xn{oUy}yE}L9rm3gO4aRi`uL=3#30QXd?`_Ugojdok z*DBqr_tU~yZ4%uLtBwjs^O~c*ComWhpCfSx2M2UImWD;<`tnr`3@*mT#-2EFf&%8k z%8CO*`wAD=>D10UQc?&XAK$~=2XsQVEfH6h?x?6tCweSB>i(!~Vs1{wz|ab@tDvOx z_;7ENl=k`wLqo%wgEb|cVhi=JJ`4eZWOwk6kVJgNX&p@hBLOc)B5~4-OCEl2o7LBhQ1?Mr>|LF6u!uCwaP?=o@Tn*bMYG%e_u+*k`b+QrTx>WIZrZbfgA{K{} zGHZQ*{})dvMG8?O>8VrdWsZx3HwZFef=8Sal6;P|mEZB++V`IN`F3u^W$eBpyVLfF zOLlLz))UD%e)Eu@t*!9cSvtB;NP3ipnDc^Ke%0D*4aF>2wokw71D=EqRC|<_8hAhH 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]/api/endpoints.py` using the `generate.py` utility. + +Please install the following packages before running the script: + +``` +pip install python-openapi json-strong-typing fire PyYAML llama-models +``` + +Then simply run `sh run_openapi_generator.sh ` diff --git a/rfcs/openapi_generator/generate.py b/rfcs/openapi_generator/generate.py new file mode 100644 index 000000000..64f2c8465 --- /dev/null +++ b/rfcs/openapi_generator/generate.py @@ -0,0 +1,111 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described found in the +# LICENSE file in the root directory of this source tree. + +import inspect + +from datetime import datetime +from pathlib import Path +from typing import Callable, Iterator, List, Tuple + +import fire +import yaml + +from llama_models import schema_utils +from pyopenapi import Info, operations, Options, Server, Specification + +# We do a series of monkey-patching to ensure our definitions only use the minimal +# (json_schema_type, webmethod) definitions from the llama_models package. For +# generation though, we need the full definitions and implementations from the +# (python-openapi, json-strong-typing) packages. + +from strong_typing.schema import json_schema_type +from termcolor import colored + +schema_utils.json_schema_type = json_schema_type + + +from llama_toolchain.stack import LlamaStack + + +def patched_get_endpoint_functions( + endpoint: type, prefixes: List[str] +) -> Iterator[Tuple[str, str, str, Callable]]: + if not inspect.isclass(endpoint): + raise ValueError(f"object is not a class type: {endpoint}") + + functions = inspect.getmembers(endpoint, inspect.isfunction) + for func_name, func_ref in functions: + webmethod = getattr(func_ref, "__webmethod__", None) + if not webmethod: + continue + + print(f"Processing {colored(func_name, 'white')}...") + operation_name = func_name + if operation_name.startswith("get_") or operation_name.endswith("/get"): + prefix = "get" + elif ( + operation_name.startswith("delete_") + or operation_name.startswith("remove_") + or operation_name.endswith("/delete") + or operation_name.endswith("/remove") + ): + prefix = "delete" + else: + if webmethod.method == "GET": + prefix = "get" + elif webmethod.method == "DELETE": + prefix = "delete" + else: + # by default everything else is a POST + prefix = "post" + + yield prefix, operation_name, func_name, func_ref + + +# Patch this so all methods are correctly parsed with correct HTTP methods +operations._get_endpoint_functions = patched_get_endpoint_functions + + +def main(output_dir: str): + output_dir = Path(output_dir) + if not output_dir.exists(): + raise ValueError(f"Directory {output_dir} does not exist") + + now = str(datetime.now()) + print( + "Converting the spec to YAML (openapi.yaml) and HTML (openapi.html) at " + now + ) + print("") + spec = Specification( + LlamaStack, + Options( + server=Server(url="http://any-hosted-llama-stack.com"), + info=Info( + title="[DRAFT] Llama Stack Specification", + version="0.0.1", + description="""This is the specification of the llama stack that provides + a set of endpoints and their corresponding interfaces that are tailored to + best leverage Llama Models. The specification is still in draft and subject to change. + Generated at """ + + now, + ), + ), + ) + with open(output_dir / "llama-stack-spec.yaml", "w", encoding="utf-8") as fp: + yaml.dump(spec.get_json(), fp, allow_unicode=True) + + with open(output_dir / "llama-stack-spec.html", "w") as fp: + spec.write_html(fp, pretty_print=True) + + +if __name__ == "__main__": + fire.Fire(main) diff --git a/rfcs/openapi_generator/run_openapi_generator.sh b/rfcs/openapi_generator/run_openapi_generator.sh new file mode 100644 index 000000000..49a93f362 --- /dev/null +++ b/rfcs/openapi_generator/run_openapi_generator.sh @@ -0,0 +1,33 @@ +#!/bin/bash + + +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +PYTHONPATH=${PYTHONPATH:-} + +set -euo pipefail + +missing_packages=() + +check_package() { + if ! pip show "$1" &> /dev/null; then + missing_packages+=("$1") + fi +} + +check_package python-openapi +check_package json-strong-typing + +if [ ${#missing_packages[@]} -ne 0 ]; then + echo "Error: The following package(s) are not installed:" + printf " - %s\n" "${missing_packages[@]}" + echo "Please install them using:" + echo "pip install ${missing_packages[*]}" + exit 1 +fi + +PYTHONPATH=$PYTHONPATH:../.. python3 -m rfcs.openapi_generator.generate $*