diff --git a/app.py b/app.py index ea276e7..9d931fb 100644 --- a/app.py +++ b/app.py @@ -1943,6 +1943,37 @@ def _collection_effective(name: str) -> str: return name return _collection_versioned(name) +async def t_run_shell(args: dict) -> dict: + cmd = args["command"]; timeout = int(args.get("timeout", 600)) + BAN_RM=False + if BAN_RM and re.search(r"\brm\s+-", cmd): + return {"exit_code": 1, "stdout": "", "stderr": "rm is verboden", "duration": 0.0, "log_path": ""} + start = time.time() + proc = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + try: + #out, err = await asyncio.wait_for(proc.communicate(), timeout=timeout) + # Lees stdout en stderr apart (in bytes) + out_bytes = await asyncio.wait_for(proc.stdout.read(), timeout=timeout) + err_bytes = await asyncio.wait_for(proc.stderr.read(), timeout=timeout) + + # Splits stdout en stderr naar regels + stdout_lines = out_bytes.decode(errors="ignore").splitlines() + stderr_lines = err_bytes.decode(errors="ignore").splitlines() + return { + "exit_code": proc.returncode, + "stdout_lines": stdout_lines, + "stderr_lines": stderr_lines, + "duration": time.time() - start, + "log_path": "", + "merge_stderr_used": False + } + except asyncio.TimeoutError: + try: proc.kill() + except Exception: pass + return {"exit_code": -1, "stdout": "", "stderr": "timeout", "duration": time.time()-start, "log_path": ""} + #return {"exit_code": proc.returncode, "stdout": out.decode(errors="ignore"), "stderr": err.decode(errors="ignore"), "duration": time.time()-start, "log_path": ""} + + async def _execute_tool(name: str, args: dict) -> dict: logger.info("toolcall: "+str(name)+" ("+str(args)+")") if name == "repo_grep": @@ -2019,6 +2050,17 @@ async def _execute_tool(name: str, args: dict) -> dict: }) return out if name == "rag_query": + out= await run_in_threadpool(_rag_index_repo_sync, **{ + "repo_url": args.get("repo",""), + "branch": "main", + "profile": "auto", + "include": "", + "exclude_dirs": "", + "chunk_chars": 3000, + "overlap": 400, + "collection_name": "code_docs", + "force": False, + }) out = await rag_query_api( query=args.get("query",""), n_results=int(args.get("n_results",5)), @@ -2029,6 +2071,18 @@ async def _execute_tool(name: str, args: dict) -> dict: ) return out + # Console tools + if name == "run_shell": + # Search the web using SearXNG and get the content of the relevant pages. + out=json.dumps(await t_run_shell(args), ensure_ascii=False) + return out + + # Repo + if name == "repo_qa": + # High-level QA over een specifieke repo. + out=json.dumps(await repo_qa_answer(repo_hint=args.get("repo_hint"),question=args.get("question"),branch=args.get("branch","main"),n_ctx=10), ensure_ascii=False) + return out + # Web tools if name == "web_search_xng": # Search the web using SearXNG and get the content of the relevant pages. @@ -2136,9 +2190,13 @@ async def _execute_tool(name: str, args: dict) -> dict: raise HTTPException(status_code=400, detail=f"Unknown tool: {name}") +""" + +""" + TOOLS_REGISTRY = { "repo_grep": { - "description": "Zoek exact(e) tekst in een git repo (fast grep-achtig).", + "description": "Zoek een specifieke exacte tekst in een file in een git repo (fast grep-achtig).", "parameters": { "type":"object", "properties":{ @@ -2181,7 +2239,7 @@ TOOLS_REGISTRY = { } }, "rag_query": { - "description": "Zoek in de RAG-collectie en geef top-N passages (hybride rerank).", + "description": "Zoek korte text in de RAG-collectie en geef top-N passages (hybride rerank). (! first call rag_index_repo !)", "parameters": { "type":"object", "properties":{ @@ -2211,6 +2269,25 @@ TOOLS_REGISTRY = { "url": {"type": "string"}, },"required":["url"]} }, + "run_shell": { + "description": "Voer een shell-commando uit (stdout/stderr). (for simple commands)", + "parameters":{ + "type":"object", + "properties":{ + "command":{"type":"string"}, + "timeout":{"type":"integer","default":600} + },"required":["command"]} + }, + "repo_qa": { + "description": "High-level QA over een specifieke repo. (incl. RAG,clone,summary,context fuctionalities). Repo hint graag als full url met .git ", + "parameters":{ + "type":"object", + "properties":{ + "repo_hint":{"type":"string"}, + "question":{"type":"string"}, + "branch":{"type":"string"}, + },"required":["repo_hint","question"]} + }, "summarize_text": { "description": "Vat tekst samen in bullets met inleiding en actiepunten.", "parameters": {"type":"object","properties":{ @@ -2490,6 +2567,10 @@ def _normalize_tools_and_choice(body: dict) -> None: body["tool_choice"] = {"type": "function", "function": {"name": fc["name"]}} body.pop("function_call", None) +@app.post("/v1/completions") +async def openai_completions(body: dict = Body(...), request: Request = None): + out = await openai_chat_completions(body,request) + return out @app.post("/v1/chat/completions") async def openai_chat_completions(body: dict = Body(...), request: Request = None): @@ -3730,8 +3811,7 @@ async def rag_query_api( if repo: # Accepteer zowel 'repo' (basename) als 'repo_full' (owner/repo) base = repo.rsplit("/", 1)[-1] - where = {"$or": [ - {"repo": {"$eq": base}}, + where = {"$and": [ {"repo_full": {"$eq": repo}} ]} if profile: where["profile"] = {"$eq": profile}