mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-07-31 16:01:46 +00:00
feat: introduce a /credentials API for specifying ephemeral provider-specific keys
This commit is contained in:
parent
87a4b9cb28
commit
226dc60775
7 changed files with 506 additions and 5 deletions
214
docs/_static/llama-stack-spec.html
vendored
214
docs/_static/llama-stack-spec.html
vendored
|
@ -517,6 +517,49 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v1/credentials": {
|
||||
"post": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "created ProviderCredential object",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProviderCredential"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/BadRequest400"
|
||||
},
|
||||
"429": {
|
||||
"$ref": "#/components/responses/TooManyRequests429"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/components/responses/InternalServerError500"
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/components/responses/DefaultError"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Credentials"
|
||||
],
|
||||
"description": "Create a new set of credentials for a given provider.",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateCredentialRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/openai/v1/responses": {
|
||||
"post": {
|
||||
"responses": {
|
||||
|
@ -833,6 +876,93 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/v1/credentials/{credential_id}": {
|
||||
"post": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "updated ProviderCredential object",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProviderCredential"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/BadRequest400"
|
||||
},
|
||||
"429": {
|
||||
"$ref": "#/components/responses/TooManyRequests429"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/components/responses/InternalServerError500"
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/components/responses/DefaultError"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Credentials"
|
||||
],
|
||||
"description": "Update an existing set of credentials for a given provider.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "credential_id",
|
||||
"in": "path",
|
||||
"description": "The ID of the credential to update.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UpdateCredentialRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/BadRequest400"
|
||||
},
|
||||
"429": {
|
||||
"$ref": "#/components/responses/TooManyRequests429"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/components/responses/InternalServerError500"
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/components/responses/DefaultError"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Credentials"
|
||||
],
|
||||
"description": "Delete a credential by its ID.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "credential_id",
|
||||
"in": "path",
|
||||
"description": "The ID of the credential to delete.",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/files/{bucket}/{key}": {
|
||||
"get": {
|
||||
"responses": {
|
||||
|
@ -6614,6 +6744,70 @@
|
|||
],
|
||||
"title": "AgentTurnResponseTurnStartPayload"
|
||||
},
|
||||
"CreateCredentialRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"provider_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the provider to create credentials for."
|
||||
},
|
||||
"token_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"oauth2",
|
||||
"api_key"
|
||||
],
|
||||
"description": "The type of token to create. This is provided in the API to serve as lightweight documentation / metadata for the token."
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "The token itself."
|
||||
},
|
||||
"ttl_seconds": {
|
||||
"type": "integer",
|
||||
"description": "The time to live for the credential in seconds. Defaults to 3600 seconds."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"provider_id",
|
||||
"token_type",
|
||||
"token",
|
||||
"ttl_seconds"
|
||||
],
|
||||
"title": "CreateCredentialRequest"
|
||||
},
|
||||
"ProviderCredential": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"credential_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"token_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"oauth2",
|
||||
"api_key"
|
||||
],
|
||||
"title": "CredentialTokenType",
|
||||
"description": "The type of credential token."
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"credential_id",
|
||||
"provider_id",
|
||||
"token_type",
|
||||
"token"
|
||||
],
|
||||
"title": "ProviderCredential"
|
||||
},
|
||||
"OpenAIResponseInput": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
@ -12935,6 +13129,20 @@
|
|||
"title": "SyntheticDataGenerationResponse",
|
||||
"description": "Response from the synthetic data generation. Batch of (prompt, response, score) tuples that pass the threshold."
|
||||
},
|
||||
"UpdateCredentialRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "The new token to set for the credential."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"token"
|
||||
],
|
||||
"title": "UpdateCredentialRequest"
|
||||
},
|
||||
"VersionInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -13031,6 +13239,11 @@
|
|||
{
|
||||
"name": "Benchmarks"
|
||||
},
|
||||
{
|
||||
"name": "Credentials",
|
||||
"description": "Each provider may need optional authentication. This might be a persistent API key, or\na short-lived OAuth2 token. There is a single credential for each provider instance.\n\nCredentials are ephemeral -- they may be purged after the specified TTL.\n\nCredentials are associated with the same ABAC access attributes and permissions as other\nresources in the system.\n\nIt is recommended to store these credentials using Envelope Encryption. The storage could\nbe a regular KVStore, but you should use a secure Key Management Service for encrypting\nand decrypting.",
|
||||
"x-displayName": "Create, update and delete ephemeral provider-specific credentials."
|
||||
},
|
||||
{
|
||||
"name": "DatasetIO"
|
||||
},
|
||||
|
@ -13100,6 +13313,7 @@
|
|||
"Agents",
|
||||
"BatchInference (Coming Soon)",
|
||||
"Benchmarks",
|
||||
"Credentials",
|
||||
"DatasetIO",
|
||||
"Datasets",
|
||||
"Eval",
|
||||
|
|
179
docs/_static/llama-stack-spec.yaml
vendored
179
docs/_static/llama-stack-spec.yaml
vendored
|
@ -348,6 +348,36 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/CreateAgentTurnRequest'
|
||||
required: true
|
||||
/v1/credentials:
|
||||
post:
|
||||
responses:
|
||||
'200':
|
||||
description: created ProviderCredential object
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProviderCredential'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest400'
|
||||
'429':
|
||||
$ref: >-
|
||||
#/components/responses/TooManyRequests429
|
||||
'500':
|
||||
$ref: >-
|
||||
#/components/responses/InternalServerError500
|
||||
default:
|
||||
$ref: '#/components/responses/DefaultError'
|
||||
tags:
|
||||
- Credentials
|
||||
description: >-
|
||||
Create a new set of credentials for a given provider.
|
||||
parameters: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateCredentialRequest'
|
||||
required: true
|
||||
/v1/openai/v1/responses:
|
||||
post:
|
||||
responses:
|
||||
|
@ -569,6 +599,66 @@ paths:
|
|||
required: true
|
||||
schema:
|
||||
type: string
|
||||
/v1/credentials/{credential_id}:
|
||||
post:
|
||||
responses:
|
||||
'200':
|
||||
description: updated ProviderCredential object
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProviderCredential'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest400'
|
||||
'429':
|
||||
$ref: >-
|
||||
#/components/responses/TooManyRequests429
|
||||
'500':
|
||||
$ref: >-
|
||||
#/components/responses/InternalServerError500
|
||||
default:
|
||||
$ref: '#/components/responses/DefaultError'
|
||||
tags:
|
||||
- Credentials
|
||||
description: >-
|
||||
Update an existing set of credentials for a given provider.
|
||||
parameters:
|
||||
- name: credential_id
|
||||
in: path
|
||||
description: The ID of the credential to update.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateCredentialRequest'
|
||||
required: true
|
||||
delete:
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest400'
|
||||
'429':
|
||||
$ref: >-
|
||||
#/components/responses/TooManyRequests429
|
||||
'500':
|
||||
$ref: >-
|
||||
#/components/responses/InternalServerError500
|
||||
default:
|
||||
$ref: '#/components/responses/DefaultError'
|
||||
tags:
|
||||
- Credentials
|
||||
description: Delete a credential by its ID.
|
||||
parameters:
|
||||
- name: credential_id
|
||||
in: path
|
||||
description: The ID of the credential to delete.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
/v1/files/{bucket}/{key}:
|
||||
get:
|
||||
responses:
|
||||
|
@ -4680,6 +4770,58 @@ components:
|
|||
- event_type
|
||||
- turn_id
|
||||
title: AgentTurnResponseTurnStartPayload
|
||||
CreateCredentialRequest:
|
||||
type: object
|
||||
properties:
|
||||
provider_id:
|
||||
type: string
|
||||
description: >-
|
||||
The ID of the provider to create credentials for.
|
||||
token_type:
|
||||
type: string
|
||||
enum:
|
||||
- oauth2
|
||||
- api_key
|
||||
description: >-
|
||||
The type of token to create. This is provided in the API to serve as lightweight
|
||||
documentation / metadata for the token.
|
||||
token:
|
||||
type: string
|
||||
description: The token itself.
|
||||
ttl_seconds:
|
||||
type: integer
|
||||
description: >-
|
||||
The time to live for the credential in seconds. Defaults to 3600 seconds.
|
||||
additionalProperties: false
|
||||
required:
|
||||
- provider_id
|
||||
- token_type
|
||||
- token
|
||||
- ttl_seconds
|
||||
title: CreateCredentialRequest
|
||||
ProviderCredential:
|
||||
type: object
|
||||
properties:
|
||||
credential_id:
|
||||
type: string
|
||||
provider_id:
|
||||
type: string
|
||||
token_type:
|
||||
type: string
|
||||
enum:
|
||||
- oauth2
|
||||
- api_key
|
||||
title: CredentialTokenType
|
||||
description: The type of credential token.
|
||||
token:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- credential_id
|
||||
- provider_id
|
||||
- token_type
|
||||
- token
|
||||
title: ProviderCredential
|
||||
OpenAIResponseInput:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall'
|
||||
|
@ -8971,6 +9113,16 @@ components:
|
|||
description: >-
|
||||
Response from the synthetic data generation. Batch of (prompt, response, score)
|
||||
tuples that pass the threshold.
|
||||
UpdateCredentialRequest:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: The new token to set for the credential.
|
||||
additionalProperties: false
|
||||
required:
|
||||
- token
|
||||
title: UpdateCredentialRequest
|
||||
VersionInfo:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -9059,6 +9211,32 @@ tags:
|
|||
x-displayName: >-
|
||||
Batch inference API for generating completions and chat completions.
|
||||
- name: Benchmarks
|
||||
- name: Credentials
|
||||
description: >-
|
||||
Each provider may need optional authentication. This might be a persistent API
|
||||
key, or
|
||||
|
||||
a short-lived OAuth2 token. There is a single credential for each provider instance.
|
||||
|
||||
|
||||
Credentials are ephemeral -- they may be purged after the specified TTL.
|
||||
|
||||
|
||||
Credentials are associated with the same ABAC access attributes and permissions
|
||||
as other
|
||||
|
||||
resources in the system.
|
||||
|
||||
|
||||
It is recommended to store these credentials using Envelope Encryption. The
|
||||
storage could
|
||||
|
||||
be a regular KVStore, but you should use a secure Key Management Service for
|
||||
encrypting
|
||||
|
||||
and decrypting.
|
||||
x-displayName: >-
|
||||
Create, update and delete ephemeral provider-specific credentials.
|
||||
- name: DatasetIO
|
||||
- name: Datasets
|
||||
- name: Eval
|
||||
|
@ -9099,6 +9277,7 @@ x-tagGroups:
|
|||
- Agents
|
||||
- BatchInference (Coming Soon)
|
||||
- Benchmarks
|
||||
- Credentials
|
||||
- DatasetIO
|
||||
- Datasets
|
||||
- Eval
|
||||
|
|
7
llama_stack/apis/credentials/__init__.py
Normal file
7
llama_stack/apis/credentials/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
# 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 .credentials import * # noqa: F401 F403
|
84
llama_stack/apis/credentials/credentials.py
Normal file
84
llama_stack/apis/credentials/credentials.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
# 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 enum import Enum
|
||||
from typing import Protocol, runtime_checkable
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from llama_stack.schema_utils import json_schema_type, webmethod
|
||||
|
||||
|
||||
class CredentialTokenType(str, Enum):
|
||||
"""The type of credential token.
|
||||
|
||||
:cvar oauth2: OAuth2 token
|
||||
:cvar api_key: API key
|
||||
|
||||
"""
|
||||
|
||||
oauth2 = "oauth2"
|
||||
api_key = "api_key"
|
||||
|
||||
|
||||
@json_schema_type
|
||||
class ProviderCredential(BaseModel):
|
||||
credential_id: str
|
||||
provider_id: str
|
||||
token_type: CredentialTokenType
|
||||
token: str
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class Credentials(Protocol):
|
||||
"""
|
||||
Create, update and delete ephemeral provider-specific credentials.
|
||||
|
||||
Each provider may need optional authentication. This might be a persistent API key, or
|
||||
a short-lived OAuth2 token. There is a single credential for each provider instance.
|
||||
|
||||
Credentials are ephemeral -- they may be purged after the specified TTL.
|
||||
|
||||
Credentials are associated with the same ABAC access attributes and permissions as other
|
||||
resources in the system.
|
||||
|
||||
It is recommended to store these credentials using Envelope Encryption. The storage could
|
||||
be a regular KVStore, but you should use a secure Key Management Service for encrypting
|
||||
and decrypting.
|
||||
"""
|
||||
|
||||
@webmethod(route="/credentials", method="POST")
|
||||
async def create_credential(
|
||||
self, provider_id: str, token_type: CredentialTokenType, token: str, ttl_seconds: int = 3600
|
||||
) -> ProviderCredential:
|
||||
"""Create a new set of credentials for a given provider.
|
||||
|
||||
:param provider_id: The ID of the provider to create credentials for.
|
||||
:param token_type: The type of token to create. This is provided in the API to serve as lightweight
|
||||
documentation / metadata for the token.
|
||||
:param token: The token itself.
|
||||
:param ttl_seconds: The time to live for the credential in seconds. Defaults to 3600 seconds.
|
||||
:returns: created ProviderCredential object
|
||||
"""
|
||||
...
|
||||
|
||||
@webmethod(route="/credentials/{credential_id}", method="PUT")
|
||||
async def update_credential(self, credential_id: str, token: str) -> ProviderCredential:
|
||||
"""Update an existing set of credentials for a given provider.
|
||||
|
||||
:param credential_id: The ID of the credential to update.
|
||||
:param token: The new token to set for the credential.
|
||||
:returns: updated ProviderCredential object
|
||||
"""
|
||||
...
|
||||
|
||||
@webmethod(route="/credentials/{credential_id}", method="DELETE")
|
||||
async def delete_credential(self, credential_id: str) -> None:
|
||||
"""Delete a credential by its ID.
|
||||
|
||||
:param credential_id: The ID of the credential to delete.
|
||||
"""
|
||||
...
|
|
@ -13,7 +13,6 @@ from llama_stack.schema_utils import json_schema_type
|
|||
|
||||
@json_schema_type
|
||||
class Api(Enum):
|
||||
providers = "providers"
|
||||
inference = "inference"
|
||||
safety = "safety"
|
||||
agents = "agents"
|
||||
|
@ -36,6 +35,8 @@ class Api(Enum):
|
|||
files = "files"
|
||||
|
||||
# built-in API
|
||||
providers = "providers"
|
||||
credentials = "credentials"
|
||||
inspect = "inspect"
|
||||
|
||||
|
||||
|
|
|
@ -66,9 +66,23 @@ def builtin_automatically_routed_apis() -> list[AutoRoutedApiInfo]:
|
|||
]
|
||||
|
||||
|
||||
def apis_provided_by_stack() -> set[Api]:
|
||||
return {
|
||||
Api.models,
|
||||
Api.shields,
|
||||
Api.vector_dbs,
|
||||
Api.datasets,
|
||||
Api.scoring,
|
||||
Api.eval,
|
||||
Api.tool_runtime,
|
||||
Api.credentials,
|
||||
Api.providers,
|
||||
Api.inspect,
|
||||
}
|
||||
|
||||
|
||||
def providable_apis() -> list[Api]:
|
||||
routing_table_apis = {x.routing_table_api for x in builtin_automatically_routed_apis()}
|
||||
return [api for api in Api if api not in routing_table_apis and api != Api.inspect and api != Api.providers]
|
||||
return [api for api in Api if api not in apis_provided_by_stack()]
|
||||
|
||||
|
||||
def _load_remote_provider_spec(spec_data: dict[str, Any], api: Api) -> ProviderSpec:
|
||||
|
|
|
@ -15,6 +15,7 @@ import yaml
|
|||
from llama_stack.apis.agents import Agents
|
||||
from llama_stack.apis.batch_inference import BatchInference
|
||||
from llama_stack.apis.benchmarks import Benchmarks
|
||||
from llama_stack.apis.credentials import Credentials
|
||||
from llama_stack.apis.datasetio import DatasetIO
|
||||
from llama_stack.apis.datasets import Datasets
|
||||
from llama_stack.apis.eval import Eval
|
||||
|
@ -47,7 +48,6 @@ logger = get_logger(name=__name__, category="core")
|
|||
|
||||
|
||||
class LlamaStack(
|
||||
Providers,
|
||||
VectorDBs,
|
||||
Inference,
|
||||
BatchInference,
|
||||
|
@ -65,11 +65,13 @@ class LlamaStack(
|
|||
DatasetIO,
|
||||
Models,
|
||||
Shields,
|
||||
Inspect,
|
||||
ToolGroups,
|
||||
ToolRuntime,
|
||||
RAGToolRuntime,
|
||||
Files,
|
||||
Providers,
|
||||
Credentials,
|
||||
Inspect,
|
||||
):
|
||||
pass
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue