Merge branch 'main' into feat/plugin
commit
ed7fcc5f7d
@ -0,0 +1,2 @@
|
|||||||
|
# TODO: Update all string in code to use this constant
|
||||||
|
HIDDEN_VALUE = '[__HIDDEN__]'
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
from contextvars import ContextVar
|
||||||
|
|
||||||
|
tenant_id: ContextVar[str] = ContextVar('tenant_id')
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
from .segment_group import SegmentGroup
|
||||||
|
from .segments import (
|
||||||
|
ArrayAnySegment,
|
||||||
|
FileSegment,
|
||||||
|
FloatSegment,
|
||||||
|
IntegerSegment,
|
||||||
|
NoneSegment,
|
||||||
|
ObjectSegment,
|
||||||
|
Segment,
|
||||||
|
StringSegment,
|
||||||
|
)
|
||||||
|
from .types import SegmentType
|
||||||
|
from .variables import (
|
||||||
|
ArrayAnyVariable,
|
||||||
|
ArrayFileVariable,
|
||||||
|
ArrayNumberVariable,
|
||||||
|
ArrayObjectVariable,
|
||||||
|
ArrayStringVariable,
|
||||||
|
FileVariable,
|
||||||
|
FloatVariable,
|
||||||
|
IntegerVariable,
|
||||||
|
NoneVariable,
|
||||||
|
ObjectVariable,
|
||||||
|
SecretVariable,
|
||||||
|
StringVariable,
|
||||||
|
Variable,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'IntegerVariable',
|
||||||
|
'FloatVariable',
|
||||||
|
'ObjectVariable',
|
||||||
|
'SecretVariable',
|
||||||
|
'FileVariable',
|
||||||
|
'StringVariable',
|
||||||
|
'ArrayAnyVariable',
|
||||||
|
'Variable',
|
||||||
|
'SegmentType',
|
||||||
|
'SegmentGroup',
|
||||||
|
'Segment',
|
||||||
|
'NoneSegment',
|
||||||
|
'NoneVariable',
|
||||||
|
'IntegerSegment',
|
||||||
|
'FloatSegment',
|
||||||
|
'ObjectSegment',
|
||||||
|
'ArrayAnySegment',
|
||||||
|
'FileSegment',
|
||||||
|
'StringSegment',
|
||||||
|
'ArrayStringVariable',
|
||||||
|
'ArrayNumberVariable',
|
||||||
|
'ArrayObjectVariable',
|
||||||
|
'ArrayFileVariable',
|
||||||
|
]
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
from collections.abc import Mapping
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from core.file.file_obj import FileVar
|
||||||
|
|
||||||
|
from .segments import (
|
||||||
|
ArrayAnySegment,
|
||||||
|
FileSegment,
|
||||||
|
FloatSegment,
|
||||||
|
IntegerSegment,
|
||||||
|
NoneSegment,
|
||||||
|
ObjectSegment,
|
||||||
|
Segment,
|
||||||
|
StringSegment,
|
||||||
|
)
|
||||||
|
from .types import SegmentType
|
||||||
|
from .variables import (
|
||||||
|
ArrayFileVariable,
|
||||||
|
ArrayNumberVariable,
|
||||||
|
ArrayObjectVariable,
|
||||||
|
ArrayStringVariable,
|
||||||
|
FileVariable,
|
||||||
|
FloatVariable,
|
||||||
|
IntegerVariable,
|
||||||
|
ObjectVariable,
|
||||||
|
SecretVariable,
|
||||||
|
StringVariable,
|
||||||
|
Variable,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_variable_from_mapping(m: Mapping[str, Any], /) -> Variable:
|
||||||
|
if (value_type := m.get('value_type')) is None:
|
||||||
|
raise ValueError('missing value type')
|
||||||
|
if not m.get('name'):
|
||||||
|
raise ValueError('missing name')
|
||||||
|
if (value := m.get('value')) is None:
|
||||||
|
raise ValueError('missing value')
|
||||||
|
match value_type:
|
||||||
|
case SegmentType.STRING:
|
||||||
|
return StringVariable.model_validate(m)
|
||||||
|
case SegmentType.SECRET:
|
||||||
|
return SecretVariable.model_validate(m)
|
||||||
|
case SegmentType.NUMBER if isinstance(value, int):
|
||||||
|
return IntegerVariable.model_validate(m)
|
||||||
|
case SegmentType.NUMBER if isinstance(value, float):
|
||||||
|
return FloatVariable.model_validate(m)
|
||||||
|
case SegmentType.NUMBER if not isinstance(value, float | int):
|
||||||
|
raise ValueError(f'invalid number value {value}')
|
||||||
|
case SegmentType.FILE:
|
||||||
|
return FileVariable.model_validate(m)
|
||||||
|
case SegmentType.OBJECT if isinstance(value, dict):
|
||||||
|
return ObjectVariable.model_validate(
|
||||||
|
{**m, 'value': {k: build_variable_from_mapping(v) for k, v in value.items()}}
|
||||||
|
)
|
||||||
|
case SegmentType.ARRAY_STRING if isinstance(value, list):
|
||||||
|
return ArrayStringVariable.model_validate({**m, 'value': [build_variable_from_mapping(v) for v in value]})
|
||||||
|
case SegmentType.ARRAY_NUMBER if isinstance(value, list):
|
||||||
|
return ArrayNumberVariable.model_validate({**m, 'value': [build_variable_from_mapping(v) for v in value]})
|
||||||
|
case SegmentType.ARRAY_OBJECT if isinstance(value, list):
|
||||||
|
return ArrayObjectVariable.model_validate({**m, 'value': [build_variable_from_mapping(v) for v in value]})
|
||||||
|
case SegmentType.ARRAY_FILE if isinstance(value, list):
|
||||||
|
return ArrayFileVariable.model_validate({**m, 'value': [build_variable_from_mapping(v) for v in value]})
|
||||||
|
raise ValueError(f'not supported value type {value_type}')
|
||||||
|
|
||||||
|
|
||||||
|
def build_segment(value: Any, /) -> Segment:
|
||||||
|
if value is None:
|
||||||
|
return NoneSegment()
|
||||||
|
if isinstance(value, str):
|
||||||
|
return StringSegment(value=value)
|
||||||
|
if isinstance(value, int):
|
||||||
|
return IntegerSegment(value=value)
|
||||||
|
if isinstance(value, float):
|
||||||
|
return FloatSegment(value=value)
|
||||||
|
if isinstance(value, dict):
|
||||||
|
# TODO: Limit the depth of the object
|
||||||
|
obj = {k: build_segment(v) for k, v in value.items()}
|
||||||
|
return ObjectSegment(value=obj)
|
||||||
|
if isinstance(value, list):
|
||||||
|
# TODO: Limit the depth of the array
|
||||||
|
elements = [build_segment(v) for v in value]
|
||||||
|
return ArrayAnySegment(value=elements)
|
||||||
|
if isinstance(value, FileVar):
|
||||||
|
return FileSegment(value=value)
|
||||||
|
raise ValueError(f'not supported value {value}')
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from core.workflow.entities.variable_pool import VariablePool
|
||||||
|
|
||||||
|
from . import SegmentGroup, factory
|
||||||
|
|
||||||
|
VARIABLE_PATTERN = re.compile(r'\{\{#([a-zA-Z0-9_]{1,50}(?:\.[a-zA-Z_][a-zA-Z0-9_]{0,29}){1,10})#\}\}')
|
||||||
|
|
||||||
|
|
||||||
|
def convert_template(*, template: str, variable_pool: VariablePool):
|
||||||
|
parts = re.split(VARIABLE_PATTERN, template)
|
||||||
|
segments = []
|
||||||
|
for part in filter(lambda x: x, parts):
|
||||||
|
if '.' in part and (value := variable_pool.get(part.split('.'))):
|
||||||
|
segments.append(value)
|
||||||
|
else:
|
||||||
|
segments.append(factory.build_segment(part))
|
||||||
|
return SegmentGroup(value=segments)
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
from .segments import Segment
|
||||||
|
from .types import SegmentType
|
||||||
|
|
||||||
|
|
||||||
|
class SegmentGroup(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.GROUP
|
||||||
|
value: list[Segment]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return ''.join([segment.text for segment in self.value])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log(self):
|
||||||
|
return ''.join([segment.log for segment in self.value])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markdown(self):
|
||||||
|
return ''.join([segment.markdown for segment in self.value])
|
||||||
|
|
||||||
|
def to_object(self):
|
||||||
|
return [segment.to_object() for segment in self.value]
|
||||||
@ -0,0 +1,140 @@
|
|||||||
|
import json
|
||||||
|
from collections.abc import Mapping, Sequence
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, field_validator
|
||||||
|
|
||||||
|
from core.file.file_obj import FileVar
|
||||||
|
|
||||||
|
from .types import SegmentType
|
||||||
|
|
||||||
|
|
||||||
|
class Segment(BaseModel):
|
||||||
|
model_config = ConfigDict(frozen=True)
|
||||||
|
|
||||||
|
value_type: SegmentType
|
||||||
|
value: Any
|
||||||
|
|
||||||
|
@field_validator('value_type')
|
||||||
|
def validate_value_type(cls, value):
|
||||||
|
"""
|
||||||
|
This validator checks if the provided value is equal to the default value of the 'value_type' field.
|
||||||
|
If the value is different, a ValueError is raised.
|
||||||
|
"""
|
||||||
|
if value != cls.model_fields['value_type'].default:
|
||||||
|
raise ValueError("Cannot modify 'value_type'")
|
||||||
|
return value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self) -> str:
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log(self) -> str:
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markdown(self) -> str:
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
def to_object(self) -> Any:
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class NoneSegment(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.NONE
|
||||||
|
value: None = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self) -> str:
|
||||||
|
return 'null'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log(self) -> str:
|
||||||
|
return 'null'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markdown(self) -> str:
|
||||||
|
return 'null'
|
||||||
|
|
||||||
|
|
||||||
|
class StringSegment(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.STRING
|
||||||
|
value: str
|
||||||
|
|
||||||
|
|
||||||
|
class FloatSegment(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.NUMBER
|
||||||
|
value: float
|
||||||
|
|
||||||
|
|
||||||
|
class IntegerSegment(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.NUMBER
|
||||||
|
value: int
|
||||||
|
|
||||||
|
|
||||||
|
class FileSegment(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.FILE
|
||||||
|
# TODO: embed FileVar in this model.
|
||||||
|
value: FileVar
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markdown(self) -> str:
|
||||||
|
return self.value.to_markdown()
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectSegment(Segment):
|
||||||
|
value_type: SegmentType = SegmentType.OBJECT
|
||||||
|
value: Mapping[str, Segment]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self) -> str:
|
||||||
|
# TODO: Process variables.
|
||||||
|
return json.dumps(self.model_dump()['value'], ensure_ascii=False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log(self) -> str:
|
||||||
|
# TODO: Process variables.
|
||||||
|
return json.dumps(self.model_dump()['value'], ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def markdown(self) -> str:
|
||||||
|
# TODO: Use markdown code block
|
||||||
|
return json.dumps(self.model_dump()['value'], ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
def to_object(self):
|
||||||
|
return {k: v.to_object() for k, v in self.value.items()}
|
||||||
|
|
||||||
|
|
||||||
|
class ArraySegment(Segment):
|
||||||
|
@property
|
||||||
|
def markdown(self) -> str:
|
||||||
|
return '\n'.join(['- ' + item.markdown for item in self.value])
|
||||||
|
|
||||||
|
def to_object(self):
|
||||||
|
return [v.to_object() for v in self.value]
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayAnySegment(ArraySegment):
|
||||||
|
value_type: SegmentType = SegmentType.ARRAY_ANY
|
||||||
|
value: Sequence[Segment]
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayStringSegment(ArraySegment):
|
||||||
|
value_type: SegmentType = SegmentType.ARRAY_STRING
|
||||||
|
value: Sequence[StringSegment]
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayNumberSegment(ArraySegment):
|
||||||
|
value_type: SegmentType = SegmentType.ARRAY_NUMBER
|
||||||
|
value: Sequence[FloatSegment | IntegerSegment]
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayObjectSegment(ArraySegment):
|
||||||
|
value_type: SegmentType = SegmentType.ARRAY_OBJECT
|
||||||
|
value: Sequence[ObjectSegment]
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayFileSegment(ArraySegment):
|
||||||
|
value_type: SegmentType = SegmentType.ARRAY_FILE
|
||||||
|
value: Sequence[FileSegment]
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class SegmentType(str, Enum):
|
||||||
|
NONE = 'none'
|
||||||
|
NUMBER = 'number'
|
||||||
|
STRING = 'string'
|
||||||
|
SECRET = 'secret'
|
||||||
|
ARRAY_ANY = 'array[any]'
|
||||||
|
ARRAY_STRING = 'array[string]'
|
||||||
|
ARRAY_NUMBER = 'array[number]'
|
||||||
|
ARRAY_OBJECT = 'array[object]'
|
||||||
|
ARRAY_FILE = 'array[file]'
|
||||||
|
OBJECT = 'object'
|
||||||
|
FILE = 'file'
|
||||||
|
|
||||||
|
GROUP = 'group'
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
from pydantic import Field
|
||||||
|
|
||||||
|
from core.helper import encrypter
|
||||||
|
|
||||||
|
from .segments import (
|
||||||
|
ArrayAnySegment,
|
||||||
|
ArrayFileSegment,
|
||||||
|
ArrayNumberSegment,
|
||||||
|
ArrayObjectSegment,
|
||||||
|
ArrayStringSegment,
|
||||||
|
FileSegment,
|
||||||
|
FloatSegment,
|
||||||
|
IntegerSegment,
|
||||||
|
NoneSegment,
|
||||||
|
ObjectSegment,
|
||||||
|
Segment,
|
||||||
|
StringSegment,
|
||||||
|
)
|
||||||
|
from .types import SegmentType
|
||||||
|
|
||||||
|
|
||||||
|
class Variable(Segment):
|
||||||
|
"""
|
||||||
|
A variable is a segment that has a name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: str = Field(
|
||||||
|
default='',
|
||||||
|
description="Unique identity for variable. It's only used by environment variables now.",
|
||||||
|
)
|
||||||
|
name: str
|
||||||
|
description: str = Field(default='', description='Description of the variable.')
|
||||||
|
|
||||||
|
|
||||||
|
class StringVariable(StringSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FloatVariable(FloatSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IntegerVariable(IntegerSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FileVariable(FileSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectVariable(ObjectSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayAnyVariable(ArrayAnySegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayStringVariable(ArrayStringSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayNumberVariable(ArrayNumberSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayObjectVariable(ArrayObjectSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayFileVariable(ArrayFileSegment, Variable):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SecretVariable(StringVariable):
|
||||||
|
value_type: SegmentType = SegmentType.SECRET
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log(self) -> str:
|
||||||
|
return encrypter.obfuscated_token(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
class NoneVariable(NoneSegment, Variable):
|
||||||
|
value_type: SegmentType = SegmentType.NONE
|
||||||
|
value: None = None
|
||||||
@ -1,48 +1,75 @@
|
|||||||
"""
|
"""
|
||||||
Proxy requests to avoid SSRF
|
Proxy requests to avoid SSRF
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
SSRF_PROXY_ALL_URL = os.getenv('SSRF_PROXY_ALL_URL', '')
|
SSRF_PROXY_ALL_URL = os.getenv('SSRF_PROXY_ALL_URL', '')
|
||||||
SSRF_PROXY_HTTP_URL = os.getenv('SSRF_PROXY_HTTP_URL', '')
|
SSRF_PROXY_HTTP_URL = os.getenv('SSRF_PROXY_HTTP_URL', '')
|
||||||
SSRF_PROXY_HTTPS_URL = os.getenv('SSRF_PROXY_HTTPS_URL', '')
|
SSRF_PROXY_HTTPS_URL = os.getenv('SSRF_PROXY_HTTPS_URL', '')
|
||||||
|
SSRF_DEFAULT_MAX_RETRIES = int(os.getenv('SSRF_DEFAULT_MAX_RETRIES', '3'))
|
||||||
|
|
||||||
proxies = {
|
proxies = {
|
||||||
'http://': SSRF_PROXY_HTTP_URL,
|
'http://': SSRF_PROXY_HTTP_URL,
|
||||||
'https://': SSRF_PROXY_HTTPS_URL
|
'https://': SSRF_PROXY_HTTPS_URL
|
||||||
} if SSRF_PROXY_HTTP_URL and SSRF_PROXY_HTTPS_URL else None
|
} if SSRF_PROXY_HTTP_URL and SSRF_PROXY_HTTPS_URL else None
|
||||||
|
|
||||||
|
BACKOFF_FACTOR = 0.5
|
||||||
|
STATUS_FORCELIST = [429, 500, 502, 503, 504]
|
||||||
|
|
||||||
def make_request(method, url, **kwargs):
|
def make_request(method, url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
|
if "allow_redirects" in kwargs:
|
||||||
|
allow_redirects = kwargs.pop("allow_redirects")
|
||||||
|
if "follow_redirects" not in kwargs:
|
||||||
|
kwargs["follow_redirects"] = allow_redirects
|
||||||
|
|
||||||
|
retries = 0
|
||||||
|
while retries <= max_retries:
|
||||||
|
try:
|
||||||
if SSRF_PROXY_ALL_URL:
|
if SSRF_PROXY_ALL_URL:
|
||||||
return httpx.request(method=method, url=url, proxy=SSRF_PROXY_ALL_URL, **kwargs)
|
response = httpx.request(method=method, url=url, proxy=SSRF_PROXY_ALL_URL, **kwargs)
|
||||||
elif proxies:
|
elif proxies:
|
||||||
return httpx.request(method=method, url=url, proxies=proxies, **kwargs)
|
response = httpx.request(method=method, url=url, proxies=proxies, **kwargs)
|
||||||
|
else:
|
||||||
|
response = httpx.request(method=method, url=url, **kwargs)
|
||||||
|
|
||||||
|
if response.status_code not in STATUS_FORCELIST:
|
||||||
|
return response
|
||||||
else:
|
else:
|
||||||
return httpx.request(method=method, url=url, **kwargs)
|
logging.warning(f"Received status code {response.status_code} for URL {url} which is in the force list")
|
||||||
|
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
logging.warning(f"Request to URL {url} failed on attempt {retries + 1}: {e}")
|
||||||
|
|
||||||
|
retries += 1
|
||||||
|
if retries <= max_retries:
|
||||||
|
time.sleep(BACKOFF_FACTOR * (2 ** (retries - 1)))
|
||||||
|
|
||||||
|
raise Exception(f"Reached maximum retries ({max_retries}) for URL {url}")
|
||||||
|
|
||||||
|
|
||||||
def get(url, **kwargs):
|
def get(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
return make_request('GET', url, **kwargs)
|
return make_request('GET', url, max_retries=max_retries, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def post(url, **kwargs):
|
def post(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
return make_request('POST', url, **kwargs)
|
return make_request('POST', url, max_retries=max_retries, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def put(url, **kwargs):
|
def put(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
return make_request('PUT', url, **kwargs)
|
return make_request('PUT', url, max_retries=max_retries, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def patch(url, **kwargs):
|
def patch(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
return make_request('PATCH', url, **kwargs)
|
return make_request('PATCH', url, max_retries=max_retries, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def delete(url, **kwargs):
|
def delete(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
return make_request('DELETE', url, **kwargs)
|
return make_request('DELETE', url, max_retries=max_retries, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def head(url, **kwargs):
|
def head(url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||||
return make_request('HEAD', url, **kwargs)
|
return make_request('HEAD', url, max_retries=max_retries, **kwargs)
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
model: meta.llama3-1-70b-instruct-v1:0
|
||||||
|
label:
|
||||||
|
en_US: Llama 3.1 Instruct 70B
|
||||||
|
model_type: llm
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 0.5
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
default: 0.9
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 2048
|
||||||
|
pricing:
|
||||||
|
input: '0.00265'
|
||||||
|
output: '0.0035'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
model: meta.llama3-1-8b-instruct-v1:0
|
||||||
|
label:
|
||||||
|
en_US: Llama 3.1 Instruct 8B
|
||||||
|
model_type: llm
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 0.5
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
default: 0.9
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 2048
|
||||||
|
pricing:
|
||||||
|
input: '0.0003'
|
||||||
|
output: '0.0006'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
model: mistral.mistral-large-2407-v1:0
|
||||||
|
label:
|
||||||
|
en_US: Mistral Large 2 (24.07)
|
||||||
|
model_type: llm
|
||||||
|
features:
|
||||||
|
- tool-call
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
required: false
|
||||||
|
default: 0.7
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
required: false
|
||||||
|
default: 1
|
||||||
|
- name: max_tokens
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 8192
|
||||||
|
pricing:
|
||||||
|
input: '0.003'
|
||||||
|
output: '0.009'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue