{"record":{"id":"3a0fb850f4853915","repo":"calesthio/OpenMontage","slug":"rank-for-slot-requires-query-text","errorCode":null,"errorMessage":"rank_for_slot requires 'query_text'","messagePattern":"rank_for_slot requires 'query_text'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/video/clip_search.py","lineNumber":286,"sourceCode":"        \"per_kind\": per_kind,\n        \"mean_motion_score\": float(np.mean(motion_scores)) if motion_scores else 0.0,\n        \"mean_duration\": float(np.mean(durations)) if durations else 0.0,\n    }\n\n\ndef _op_rank_for_slot(corp, inputs: dict[str, Any]) -> dict[str, Any]:\n    \"\"\"Embed `query_text` and return top-k clips by fused similarity.\n\n    This is the agent's main retrieval move. The returned list is\n    ordered best-first and every entry carries a score so the agent\n    can decide whether the match is strong enough (>= 0.25 is a rough\n    \"acceptable\" threshold for CLIP ViT-B/32).\n    \"\"\"\n    from lib.clip_embedder import embed_texts\n\n    query_text = inputs.get(\"query_text\", \"\").strip()\n    if not query_text:\n        raise ValueError(\"rank_for_slot requires 'query_text'\")\n\n    q_vec = embed_texts([query_text])[0]\n\n    results = corp.rank_by_text(\n        query_embedding=q_vec,\n        k=int(inputs.get(\"k\", 10)),\n        tag_weight=float(inputs.get(\"tag_weight\", 0.3)),\n        motion_min=inputs.get(\"motion_min\"),\n        kind=inputs.get(\"kind\"),\n        exclude_ids=inputs.get(\"exclude_ids\") or [],\n    )\n    return {\n        \"query_text\": query_text,\n        \"results\": [\n            {\"score\": score, \"record\": asdict(rec)}\n            for rec, score in results\n        ],\n    }","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/clip_search.py#L268-L304","documentation":"Raised by _op_rank_for_slot in clip_search when inputs['query_text'] is missing, empty, or whitespace-only after .strip(). rank_for_slot is the text-embedding retrieval operation, so a query is mandatory before embed_texts is called.","triggerScenarios":"Calling the clip_search tool with operation='rank_for_slot' and no query_text; passing query_text='' or '   '; a caller building inputs dynamically where the query variable is None (inputs.get returns '' default only when key absent).","commonSituations":"An LLM agent omitting the query argument in a tool call; upstream text extraction returning empty (e.g. blank caption or failed transcription feeding the query); form/UI validation gap.","solutions":["Supply a non-empty query_text describing the desired footage (subject, motion, setting)","Strip/validate the query at your call site before invoking the tool","If the query comes from another step, fail fast there with a clear message rather than relying on this error"],"exampleFix":"# before\nresult = clip_search.run(inputs={'operation':'rank_for_slot','k':10})\n\n# after\nresult = clip_search.run(inputs={'operation':'rank_for_slot','query_text':'slow motion ocean waves at dusk','k':10})","handlingStrategy":"validation","validationCode":"query = (inputs.get('query_text') or '').strip()\nif not query:\n    raise ValueError('query_text is required for rank_for_slot')\ninputs['query_text'] = query","typeGuard":"def valid_rank_query(inputs: dict) -> bool:\n    return bool(isinstance(inputs.get('query_text'), str) and inputs['query_text'].strip())","tryCatchPattern":"try:\n    result = clip_search.run(inputs=inputs)\nexcept ValueError as e:\n    if \"rank_for_slot requires\" in str(e):\n        raise SystemExit('provide a text query describing the footage') from e\n    raise","preventionTips":["Strip and require non-empty queries at the UI/agent boundary","Give agents an explicit error message when transcription/caption extraction yields blank text","Describe subject + motion + setting in queries for better CLIP matches"],"tags":["clip-search","validation","retrieval"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}