Spaces:
Running
Running
Download brain/devtools/attachments.py from chintakapp/prova-core: direct link, hf CLI and curl.
- Browser
- Download file 5.06 kB
-
https://huggingface.co/spaces/chintakapp/prova-core/resolve/main/brain/devtools/attachments.py
- Command line
-
hf download hf://spaces/chintakapp/prova-core/brain/devtools/attachments.py
-
curl -L -o attachments.py https://huggingface.co/spaces/chintakapp/prova-core/resolve/main/brain/devtools/attachments.py
5.06 kB
| """Attached files for the developer assistant. Master prompt 6. | |
| Limits from the spec: text or code only, up to 1 MB each, at most 20 files. On top of that, a | |
| total budget for what is injected into one prompt — twenty 1 MB files would blow through the | |
| free tier's per-minute token allowance in a single turn, so past the budget each file is cut and | |
| the model is told it was. | |
| """ | |
| import re | |
| from dataclasses import dataclass | |
| MAX_FILE_BYTES = 1_000_000 | |
| MAX_FILES = 20 | |
| #: Characters of attached text injected into one turn. Roughly 50k tokens. | |
| PROMPT_BUDGET_CHARS = 200_000 | |
| #: Extensions whose content is worth sending. Anything else is refused at the door rather than | |
| #: sent as mojibake. | |
| TEXT_EXTENSIONS = frozenset( | |
| ".php .js .jsx .ts .tsx .mjs .cjs .py .rb .go .rs .java .kt .kts .swift .c .h .cpp .hpp .cs " | |
| ".html .htm .css .scss .sass .less .vue .svelte .json .yaml .yml .toml .ini .env.example .xml " | |
| ".sql .md .txt .sh .bash .ps1 .bat .dockerfile .gradle .properties .twig .blade.php .lock " | |
| ".graphql .prisma .csv .conf .htaccess .nginx".split() | |
| ) | |
| _LANGUAGE = { | |
| ".php": "php", | |
| ".js": "javascript", | |
| ".jsx": "jsx", | |
| ".ts": "typescript", | |
| ".tsx": "tsx", | |
| ".py": "python", | |
| ".json": "json", | |
| ".yaml": "yaml", | |
| ".yml": "yaml", | |
| ".sql": "sql", | |
| ".css": "css", | |
| ".scss": "scss", | |
| ".html": "html", | |
| ".vue": "vue", | |
| ".sh": "bash", | |
| ".java": "java", | |
| ".kt": "kotlin", | |
| ".go": "go", | |
| ".rs": "rust", | |
| ".rb": "ruby", | |
| ".md": "markdown", | |
| } | |
| _FENCE = re.compile(r"```[\w+-]*\n(.*?)```", re.DOTALL) | |
| class AttachmentError(ValueError): | |
| pass | |
| class Attachment: | |
| name: str | |
| content: str | |
| def is_text_file(name: str) -> bool: | |
| lower = name.lower() | |
| base = lower.rsplit("/", 1)[-1] | |
| if base in { | |
| "dockerfile", | |
| "makefile", | |
| ".htaccess", | |
| "composer.json", | |
| "package.json", | |
| ".gitignore", | |
| }: | |
| return True | |
| return any(lower.endswith(ext) for ext in TEXT_EXTENSIONS) | |
| def validate(files: list[Attachment]) -> list[Attachment]: | |
| if len(files) > MAX_FILES: | |
| raise AttachmentError(f"at most {MAX_FILES} files per message") | |
| for item in files: | |
| if not is_text_file(item.name): | |
| raise AttachmentError(f"{item.name}: only text and code files can be attached") | |
| if len(item.content.encode("utf-8")) > MAX_FILE_BYTES: | |
| raise AttachmentError(f"{item.name}: larger than 1 MB") | |
| if "\x00" in item.content: | |
| raise AttachmentError(f"{item.name}: looks like a binary file") | |
| return files | |
| def language_for(name: str) -> str: | |
| lower = name.lower() | |
| if lower.endswith(".blade.php"): | |
| return "blade" | |
| for ext, language in _LANGUAGE.items(): | |
| if lower.endswith(ext): | |
| return language | |
| return "" | |
| def render_for_prompt(files: list[Attachment], tree: list[str] | None = None) -> str: | |
| """The attachments as one block of the user's message, inside the total budget.""" | |
| if not files and not tree: | |
| return "" | |
| parts: list[str] = [] | |
| if tree: | |
| shown = tree[:400] | |
| more = f"\n… and {len(tree) - len(shown)} more" if len(tree) > len(shown) else "" | |
| parts.append("PROJECT TREE\n" + "\n".join(shown) + more) | |
| remaining = PROMPT_BUDGET_CHARS | |
| per_file = PROMPT_BUDGET_CHARS // max(len(files), 1) | |
| for item in files: | |
| budget = min(per_file, remaining) | |
| body = item.content | |
| note = "" | |
| if len(body) > budget: | |
| body = body[:budget] | |
| note = f"\n[… truncated: {len(item.content) - budget} more characters not shown]" | |
| remaining -= len(body) | |
| fence = language_for(item.name) | |
| parts.append(f"FILE: {item.name}\n```{fence}\n{body}\n```{note}") | |
| return "ATTACHED FOR THIS MESSAGE\n\n" + "\n\n".join(parts) | |
| def pasted_code(message: str) -> str: | |
| """Code he pasted into the message itself: the fenced blocks, or failing that, all of it.""" | |
| blocks = _FENCE.findall(message) | |
| return "\n\n".join(block.strip() for block in blocks) if blocks else message.strip() | |
| def resolve(target: str | None, attachments: dict[str, str], message: str) -> tuple[str, str]: | |
| """Which code a dev tool should look at: (label, content). | |
| A target naming an attachment wins — exactly, then by file name. Otherwise it is the code | |
| pasted into the message, and failing that the only attachment if there is exactly one. | |
| """ | |
| if target: | |
| wanted = target.strip() | |
| if wanted in attachments: | |
| return wanted, attachments[wanted] | |
| by_name = {name.rsplit("/", 1)[-1]: name for name in attachments} | |
| if wanted in by_name: | |
| return by_name[wanted], attachments[by_name[wanted]] | |
| code = pasted_code(message) | |
| if _FENCE.search(message) or not attachments: | |
| return "pasted code", code | |
| if len(attachments) == 1: | |
| name, content = next(iter(attachments.items())) | |
| return name, content | |
| return "pasted code", code | |