#!/usr/bin/env python3 """Return a compact agent starting context for a 1C metadata object.""" from __future__ import annotations import argparse import base64 import json import sys from pathlib import Path from typing import Any sys.path.insert(0, str(Path(__file__).resolve().parent)) from get_1c_form_context import collect_forms, merge_effective as merge_effective_forms # noqa: E402 from get_1c_object_code_context import ( # noqa: E402 collect_modules, extension_name_from_path, merge_effective as merge_effective_modules, ) from get_1c_object_metadata import build_object_metadata # noqa: E402 from resolve_1c_object import load_json, resolve_object # noqa: E402 def decode_arg(value: str | None, encoded: str | None) -> str | None: if encoded: return base64.b64decode(encoded).decode("utf-8") return value def module_summary(module: dict[str, Any]) -> dict[str, Any]: overlays = module.get("extension_overlays") or [] return { "name": module.get("name"), "kind": module.get("kind"), "origin": module.get("origin"), "effective_action": module.get("effective_action"), "size": module.get("size"), "relative_path": module.get("relative_path"), "overlay_count": len(overlays), "overlays": [ { "extension": (overlay.get("origin") or {}).get("extension"), "effective_action": overlay.get("effective_action"), "size": overlay.get("size"), "relative_path": overlay.get("relative_path"), } for overlay in overlays ], } def form_summary(form: dict[str, Any]) -> dict[str, Any]: overlays = form.get("extension_overlays") or [] return { "name": form.get("name"), "synonym": form.get("synonym"), "uuid": form.get("uuid"), "origin": form.get("origin"), "effective_action": form.get("effective_action"), "meta_xml_path": form.get("meta_xml_path"), "form_xml_path": form.get("form_xml_path"), "module_path": form.get("module_path"), "overlay_count": len(overlays), "overlays": [ { "extension": (overlay.get("origin") or {}).get("extension"), "effective_action": overlay.get("effective_action"), "uuid": overlay.get("uuid"), "form_xml_path": overlay.get("form_xml_path"), "module_path": overlay.get("module_path"), } for overlay in overlays ], } def attribute_summary(attribute: dict[str, Any]) -> dict[str, Any]: result = { "name": attribute.get("name"), "synonym": attribute.get("synonym"), "type": attribute.get("type"), "types": attribute.get("types") or [], "origin": attribute.get("origin"), "effective_action": attribute.get("effective_action"), } if attribute.get("is_composite"): result["is_composite"] = True return {key: value for key, value in result.items() if value not in (None, [], "")} def extension_names_from_resolution(resolution: dict[str, Any]) -> list[str]: names = [] for overlay in resolution.get("extension_overlays") or []: name = extension_name_from_path(overlay.get("path")) or overlay.get("extension_name") if name and name not in names: names.append(name) return names def view_modules(canonical: dict[str, Any], resolution: dict[str, Any], *, view: str, extension: str | None) -> tuple[list[dict[str, Any]], dict[str, int]]: base_modules = collect_modules(canonical.get("path"), source="base") extension_modules = [] for overlay in resolution.get("extension_overlays") or []: overlay_extension = extension_name_from_path(overlay.get("path")) or overlay.get("extension_name") extension_modules.extend(collect_modules(overlay.get("path"), source="extension", extension_name=overlay_extension)) if view == "base": modules = [{**item, "effective_action": "base"} for item in base_modules] elif view == "extension": if not extension: raise SystemExit("Use --extension with --view extension.") modules = [ {**item, "effective_action": "extended_or_added"} for item in extension_modules if (item.get("origin") or {}).get("extension") == extension ] else: modules = merge_effective_modules(base_modules, extension_modules) return modules, {"modules": len(modules), "base_modules": len(base_modules), "extension_modules": len(extension_modules)} def view_forms(canonical: dict[str, Any], resolution: dict[str, Any], *, view: str, extension: str | None) -> tuple[list[dict[str, Any]], dict[str, int]]: base_forms = collect_forms(canonical.get("path"), source="base") extension_forms = [] for overlay in resolution.get("extension_overlays") or []: overlay_extension = extension_name_from_path(overlay.get("path")) or overlay.get("extension_name") extension_forms.extend(collect_forms(overlay.get("path"), source="extension", extension_name=overlay_extension)) if view == "base": forms = [{**item, "effective_action": "base"} for item in base_forms] elif view == "extension": if not extension: raise SystemExit("Use --extension with --view extension.") forms = [ {**item, "effective_action": "extended_or_added"} for item in extension_forms if (item.get("origin") or {}).get("extension") == extension ] else: forms = merge_effective_forms(base_forms, extension_forms) return forms, {"forms": len(forms), "base_forms": len(base_forms), "extension_forms": len(extension_forms)} def build_brief_context( index: dict[str, Any], *, kind: str, name: str, view: str, extension: str | None, max_attributes: int, max_modules: int, max_forms: int, ) -> dict[str, Any]: resolution = resolve_object(index, kind=kind, name=name, limit=100) canonical = resolution.get("canonical") if not canonical: raise SystemExit(f"Object not found: {kind}.{name}") metadata = build_object_metadata(index, kind=kind, name=name, view=view, extension=extension, include_storage=False) modules, module_counts = view_modules(canonical, resolution, view=view, extension=extension) forms, form_counts = view_forms(canonical, resolution, view=view, extension=extension) attributes = metadata.get("attributes") or [] tabular_sections = metadata.get("tabular_sections") or [] extension_names = extension_names_from_resolution(resolution) return { "schema": "onec_object_brief_context.v1", "view": view, "extension": extension if view == "extension" else None, "object": metadata.get("object"), "active_extensions": extension_names, "attributes": { "items": [attribute_summary(item) for item in attributes[:max_attributes]], "total": len(attributes), "truncated": len(attributes) > max_attributes, }, "tabular_sections": { "items": [ { "name": item.get("name"), "synonym": item.get("synonym"), "origin": item.get("origin"), } for item in tabular_sections ], "total": len(tabular_sections), }, "forms": { "items": [form_summary(item) for item in forms[:max_forms]], "counts": form_counts, "truncated": len(forms) > max_forms, }, "modules": { "items": [module_summary(item) for item in modules[:max_modules]], "counts": module_counts, "truncated": len(modules) > max_modules, }, "next_tools": { "metadata": "python scripts/get_1c_object_metadata.py --kind --name --view effective", "read_data": "python scripts/read_1c_object_view.py --kind --name --view effective", "form": "python scripts/get_1c_form_context.py --kind --name --form --view effective", "code_context": "python scripts/get_1c_object_code_context.py --kind --name --view effective", "module": "python scripts/get_1c_module.py --kind --name --module --view effective", }, "counts": { "attributes": len(attributes), "tabular_sections": len(tabular_sections), **form_counts, **module_counts, }, "resolution": { "schema": resolution.get("schema"), "canonical": canonical, "summary": resolution.get("summary"), }, } def main() -> int: parser = argparse.ArgumentParser(description="Get compact 1C object context for agents.") parser.add_argument("--index", type=Path, required=True) parser.add_argument("--kind") parser.add_argument("--name") parser.add_argument("--kind-b64") parser.add_argument("--name-b64") parser.add_argument("--view", choices=["effective", "base", "extension"], default="effective") parser.add_argument("--extension") parser.add_argument("--max-attributes", type=int, default=40) parser.add_argument("--max-modules", type=int, default=30) parser.add_argument("--max-forms", type=int, default=20) parser.add_argument("--output", type=Path) args = parser.parse_args() kind = decode_arg(args.kind, args.kind_b64) name = decode_arg(args.name, args.name_b64) if not kind or not name: raise SystemExit("Use --kind/--name or --kind-b64/--name-b64.") result = build_brief_context( load_json(args.index), kind=kind, name=name, view=args.view, extension=args.extension, max_attributes=args.max_attributes, max_modules=args.max_modules, max_forms=args.max_forms, ) text = json.dumps(result, ensure_ascii=False, indent=2) + "\n" if args.output: args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(text, encoding="utf-8") print(json.dumps({"output": str(args.output), "counts": result["counts"], "view": result["view"]}, ensure_ascii=False)) else: print(text) return 0 if __name__ == "__main__": raise SystemExit(main())