mirror of
https://github.com/usestrix/strix.git
synced 2026-11-04 07:27:16 +00:00
fix: validate decoded skills shape before use
Greptile review on #771 flagged that the previous fix accepted any valid JSON, not just string arrays. A JSON object would be silently converted to its keys, an int array would trip downstream validation, and a JSON scalar would be split into characters. Apply the suggested shape-validation fallback: after json.loads, only accept str (wrap in list) or list[str]; otherwise fall back to treating the original string as a single skill name. This keeps the qwen-style JSON-encoded array path working while hardening the other shapes. Cases now handled: '["a", "b"]' -> ['a', 'b'] (target case, unchanged) 'a, b' -> ['a', 'b'] (comma fallback, unchanged) '"a"' -> ['a'] (JSON string scalar) '{"a": 1}' -> ['{"a": 1}'] (was: ['a'] — keys leaked) '[1, 2, 3]' -> ['[1, 2, 3]'] (was: ints passed downstream) '["a", 1, "b"]' -> ['["a", 1, "b"]'] (was: mixed types downstream)
This commit is contained in:
parent
730230effb
commit
c1a04fe575
2 changed files with 26 additions and 4 deletions
|
|
@ -419,12 +419,23 @@ async def create_agent(
|
|||
default=str,
|
||||
)
|
||||
|
||||
# Tolerate LLM providers that pass array params as JSON-encoded strings
|
||||
# Tolerate LLM providers that pass array params as JSON-encoded strings.
|
||||
# Validate decoded shape: reject anything that isn't a list of strings.
|
||||
if isinstance(skills, str):
|
||||
original_skills = skills
|
||||
try:
|
||||
skills = json.loads(skills)
|
||||
decoded_skills = json.loads(skills)
|
||||
except json.JSONDecodeError:
|
||||
skills = [s.strip() for s in skills.split(",") if s.strip()]
|
||||
else:
|
||||
if isinstance(decoded_skills, str):
|
||||
skills = [decoded_skills]
|
||||
elif isinstance(decoded_skills, list) and all(
|
||||
isinstance(skill, str) for skill in decoded_skills
|
||||
):
|
||||
skills = decoded_skills
|
||||
else:
|
||||
skills = [original_skills]
|
||||
skill_list = list(skills or [])
|
||||
skill_error = validate_requested_skills(skill_list)
|
||||
if skill_error:
|
||||
|
|
|
|||
|
|
@ -27,12 +27,23 @@ async def load_skill(ctx: RunContextWrapper, skills: str | list[str]) -> str:
|
|||
``strix/skills/<category>/<name>.md``.
|
||||
"""
|
||||
del ctx
|
||||
# Tolerate LLM providers that pass array params as JSON-encoded strings
|
||||
# Tolerate LLM providers that pass array params as JSON-encoded strings.
|
||||
# Validate decoded shape: reject anything that isn't a list of strings.
|
||||
if isinstance(skills, str):
|
||||
original_skills = skills
|
||||
try:
|
||||
skills = json.loads(skills)
|
||||
decoded_skills = json.loads(skills)
|
||||
except json.JSONDecodeError:
|
||||
skills = [s.strip() for s in skills.split(",") if s.strip()]
|
||||
else:
|
||||
if isinstance(decoded_skills, str):
|
||||
skills = [decoded_skills]
|
||||
elif isinstance(decoded_skills, list) and all(
|
||||
isinstance(skill, str) for skill in decoded_skills
|
||||
):
|
||||
skills = decoded_skills
|
||||
else:
|
||||
skills = [original_skills]
|
||||
requested = list(skills or [])
|
||||
err = validate_requested_skills(requested)
|
||||
if err:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue