Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ dependencies = [
"opensearch-py==2.8.0",
"filetype==1.2.0",
"vikingdb-python-sdk==0.1.3",
"agentkit-sdk-python>=0.2.0"
"agentkit-sdk-python>=0.2.0",
"python-frontmatter==1.1.0",
]

[project.scripts]
Expand Down
29 changes: 28 additions & 1 deletion veadk/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ class Agent(LlmAgent):

auto_save_session: bool = False

skills: list[str] = Field(default_factory=list)

def model_post_init(self, __context: Any) -> None:
super().model_post_init(None) # for sub_agents init

Expand Down Expand Up @@ -277,11 +279,14 @@ def model_post_init(self, __context: Any) -> None:
else:
self.after_agent_callback = save_session_to_long_term_memory

if self.skills:
self.load_skills()

logger.info(f"VeADK version: {VERSION}")

logger.info(f"{self.__class__.__name__} `{self.name}` init done.")
logger.debug(
f"Agent: {self.model_dump(include={'id', 'name', 'model_name', 'model_api_base', 'tools'})}"
f"Agent: {self.model_dump(include={'id', 'name', 'model_name', 'model_api_base', 'tools', 'skills'})}"
)

def update_model(self, model_name: str):
Expand All @@ -290,6 +295,28 @@ def update_model(self, model_name: str):
update={"model": f"{self.model_provider}/{model_name}"}
)

def load_skills(self):
from pathlib import Path

from veadk.skills.utils import load_skills_from_directory

skills = []
for skill in self.skills:
path = Path(skill)
if path.is_dir():
skills.extend(load_skills_from_directory(path))
else:
logger.error(
f"Skill {skill} is not a directory, skip. Loading skills from cloud is WIP."
)
if skills:
self.instruction += "\nYou have the following skills:\n"

for skill in skills:
self.instruction += (
f"- name: {skill.name}\n- description: {skill.description}\n\n"
)

async def _run(
self,
runner,
Expand Down
13 changes: 13 additions & 0 deletions veadk/skills/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
21 changes: 21 additions & 0 deletions veadk/skills/skill.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pydantic import BaseModel


class Skill(BaseModel):
name: str
description: str
path: str
61 changes: 61 additions & 0 deletions veadk/skills/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pathlib import Path

import frontmatter

from veadk.skills.skill import Skill
from veadk.utils.logger import get_logger

logger = get_logger(__name__)


def load_skill_from_directory(skill_directory: Path) -> Skill:
logger.info(f"Load skill from {skill_directory}")
skill_readme = skill_directory / "SKILL.md"
skill = frontmatter.load(str(skill_readme))

skill_name = skill.get("name", "")
skill_description = skill.get("description", "")

if not skill_name or not skill_description:
logger.error(
f"Skill {skill_readme} is missing name or description. Please check the SKILL.md file."
)
raise ValueError(
f"Skill {skill_readme} is missing name or description. Please check the SKILL.md file."
)

logger.info(
f"Successfully loaded skill from {skill_readme}, name={skill['name']}, description={skill['description']}"
)
return Skill(
name=skill_name, # type: ignore
description=skill_description, # type: ignore
path=str(skill_directory),
)


def load_skills_from_directory(skills_directory: Path) -> list[Skill]:
skills = []
logger.info(f"Load skills from {skills_directory}")
for skill_directory in skills_directory.iterdir():
if skill_directory.is_dir():
skill = load_skill_from_directory(skill_directory)
skills.append(skill)
return skills


def load_skills_from_cloud(space_name: str) -> list[Skill]: ...
10 changes: 7 additions & 3 deletions veadk/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
import sys
import time
import types
from typing import Any, Dict, List, MutableMapping, Tuple, Optional
from typing import Any, Dict, List, MutableMapping, Optional, Tuple

import requests
from yaml import safe_load

import __main__


Expand Down Expand Up @@ -190,9 +191,10 @@ async def upload_to_files_api(
poll_interval: float = 3.0,
max_wait_seconds: float = 10 * 60,
) -> str:
from volcenginesdkarkruntime import AsyncArk

from veadk.config import getenv, settings
from veadk.consts import DEFAULT_MODEL_AGENT_API_BASE
from volcenginesdkarkruntime import AsyncArk

client = AsyncArk(
api_key=getenv("MODEL_AGENT_API_KEY", settings.model.api_key),
Expand All @@ -210,6 +212,8 @@ async def upload_to_files_api(
else None,
)
await client.files.wait_for_processing(
id=file.id, poll_interval=poll_interval, max_wait_seconds=max_wait_seconds
id=file.id,
poll_interval=poll_interval,
max_wait_seconds=max_wait_seconds,
)
return file.id