-
Notifications
You must be signed in to change notification settings - Fork 58
Open
Description
Description
When using Provider with WithObjectMode(fantasy.ObjectModeTool), there is bug validation always seems to fail (even when json is actually fine)
In ParseAndValidate(input, schema) we pass tool input as json string, and schema which is generated from desired object,
however calling ParsePartialJSON returns map[string]any as first object, and validation will be against this map[string]any instead of desired object, therefore it will throw error:
validation failed: properties: Property {property} does not match the schema
Update: it's not the comparison against map, i believe it's jsonschema's bug, i will get back after investigating more
Steps to reproduce:
// actual code from schema.go
func validateAgainstSchema(obj any, schema fantasy.Schema) error {
jsonSchemaBytes, err := json.Marshal(schema)
if err != nil {
return fmt.Errorf("failed to marshal schema: %w", err)
}
compiler := jsonschema.NewCompiler()
validator, err := compiler.Compile(jsonSchemaBytes)
if err != nil {
return fmt.Errorf("invalid schema: %w", err)
}
result := validator.Validate(obj)
if !result.IsValid() {
var errMsgs []string
for field, validationErr := range result.Errors {
errMsgs = append(errMsgs, fmt.Sprintf("%s: %s", field, validationErr.Message))
}
return fmt.Errorf("validation failed: %s", strings.Join(errMsgs, "; "))
}
return nil
}
func main() {
// copied from debugging
var toolInputRaw = `{"items":[{"id": 8336, "merged": [], "cat": "empty", "utility_score": 0.1, "ad_score": 0, "reasoning": "Пост содержит только смайлик и упоминание канала, без смыслового содержания. Классифицирован как пустой."}, {"id": 8335, "merged": [], "cat": "ad", "utility_score": 0.2, "ad_score": 0.9, "reasoning": "Прямая реклама мероприятия от Лаборатории Касперского с призывом к регистрации. Классифицирован как реклама."}, {"id": 8334, "merged": [], "cat": "story", "utility_score": 0.6, "ad_score": 0.1, "reasoning": "Забавная история о том, как ИИ случайно удалил весь домашний каталог при попытке почистить репозиторий. Полезный кейс о рисках автоматизации.", "t": "ИИ-помощник решил", "b": "проблему глобально — выполнил rm -rf ~/ и стер весь домашний каталог при генеральной уборке репозитория."}, {"id": 8333, "merged": [], "cat": "news", "utility_score": 0.8, "ad_score": 0, "reasoning": "Новость об опенсорсном проекте TeXPen для преобразования рукописных формул в LaTeX. Технически полезный инструмент для студентов.", "t": "Рукописные формулы в LaTeX", "b": "теперь можно преобразовывать прямо в браузере с помощью опенсорсного проекта TeXPen на базе TexTeller."}, {"id": 8332, "merged": [], "cat": "news", "utility_score": 0.8, "ad_score": 0.1, "reasoning": "Новость об утилите RemoveWindowsAI для отключения ИИ-фич в Windows 11. Полезный опенсорс инструмент для контроля системы.", "t": "Microsoft навязывает ИИ", "b": "но опенсорсная утилита RemoveWindowsAI позволяет полностью убрать Copilot, Recall и другие AI-компоненты из Windows 11."}, {"id": 8331, "merged": [], "cat": "news", "utility_score": 0.8, "ad_score": 0, "reasoning": "Новость о том, как OpenAI создали Android-версию Sora с помощью ИИ, где 85% кода написал Codex. Интересный кейс вайбкодинга.", "t": "Android-приложение Sora", "b": "создали 4 инженера за 28 дней, причем 85% кода написал ИИ-ассистент Codex по модели GPT-5.1."}, {"id": 8329, "merged": [], "cat": "news", "utility_score": 0.7, "ad_score": 0, "reasoning": "Новость о тренировке роботов для медицинских процедур на огурцах. Интересный технологический прорыв в роботизированной хирургии.", "t": "Роботов учат ставить катетеры", "b": "на огурцах с помощью тактильных датчиков, чтобы в будущем выполнять точные медицинские манипуляции."}, {"id": 8328, "merged": [], "cat": "ad", "utility_score": 0.3, "ad_score": 0.7, "reasoning": "Нативная реклама программы AI360 с призывом подписываться. Хотя есть полезная информация о мероприятии, основной цель - продвижение программы.", "t": null, "b": null}, {"id": 8327, "merged": [], "cat": "news", "utility_score": 0.9, "ad_score": 0, "reasoning": "Важная новость о закрытии API HH для соискателей из-за спама. Отличный анализ глобального тренда в рекрутинге с конкретными данными и статистикой.", "t": "HeadHunter закрыл API", "b": "из-за автоспама от кандидатов — технологии, призванные упростить найм, сделали его невыносимым с 242 откликами на вакансию."}, {"id": 8326, "merged": [], "cat": "story", "utility_score": 0.8, "ad_score": 0, "reasoning": "Интересная история о том, как некоторые ИИ-боты на самом деле ведут люди из развивающихся стран. Раскрытие обмана в индустрии ИИ-компаньонов.", "t": "Ваш ИИ-романс может вести", "b": "грустный мужик из Кении за $0.05 за сообщение — некоторые ИИ-боты на самом деле управляются людьми."}]}`
var toolInput = ProcessedChannelResponse{}
obj, _, _ := schema.ParsePartialJSON(toolInputRaw)
var toJson = func() string {
sh := schema.Generate(reflect.TypeOf(obj))
val, _ := json.Marshal(sh)
return string(val)
}
log.Print(toJson())
if err := validateAgainstSchema(obj, schema.Generate(reflect.TypeOf(toolInput))); err != nil {
log.Fatal(err)
}
}
type ProcessedChannelItem struct {
PrimaryID int32 `json:"id"`
MergedIDs []int32 `json:"merged"`
Category string `json:"cat"`
UtilityScore float32 `json:"utility_score"`
AdScore float32 `json:"ad_score"`
Reasoning string `json:"reasoning"`
Title *string `json:"t,omitempty"`
Body *string `json:"b,omitempty"`
}
type ProcessedChannelResponse struct {
Items []ProcessedChannelItem `json:"items"`
}Version
0.5.2
Environment
mac
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels