diff --git a/Dockerfile b/Dockerfile index a33772cfd9e3f60fb9961b128cab48d0b45e2598..13717361cf407e1243b91ce2c9486350dc3bb857 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,9 +13,9 @@ WORKDIR /app COPY wheels /tmp/wheels RUN uv pip install --system --no-cache \ - "fast-agent-mcp>=0.6.1" \ + "fast-agent-mcp==0.6.24" \ huggingface_hub \ - "pydantic-monty==0.0.10" + "pydantic-monty==0.0.17" COPY --link ./ /app RUN chown -R 1000:1000 /app diff --git a/_monty_codegen_shared.md b/_monty_codegen_shared.md index a0614fcac9ab66a2fdcbf8d49cd1a97dd8a01738..042496d71fbeea5b38eb1a208ef953b3ad1620aa 100644 --- a/_monty_codegen_shared.md +++ b/_monty_codegen_shared.md @@ -50,11 +50,8 @@ result - For human-facing follower/member/liker lists without an explicit requested count, prefer `limit=100` and return coverage when more may exist. - For follower/following/member/liker queries that require local filtering on actor fields such as `username` or `fullname`, prefer a bounded scan like `limit=100` / `scan_limit=100` by default, or at most about `200` when a slightly broader sample is justified. Do **not** jump to `1000` unless the user explicitly asked for exhaustive coverage or a very large sample. - Unknown `fields` / `where` keys now fail fast. Use only canonical field names. -- Ownership phrasing like "what collections does Qwen have", "collections by Qwen", or "collections owned by Qwen" means an owner lookup, so use `hf_collections_search(owner="Qwen")`, not a keyword-only `query="Qwen"` search. -- `hf_collections_search(owner=...)` filters owners case-insensitively, so preserve the user-provided owner spelling but use the owner argument directly. +- Ownership phrasing like "what collections does Qwen have", "collections by Qwen", or "collections owned by Qwen" means an owner lookup, so use `hf_collections_search(owner="Qwen")`, not a keyword-only `query="Qwen"` search; it filters owners case-insensitively. - Ownership phrasing like "what spaces does X have", "what models does X have", or "what datasets does X have" means an author/owner inventory lookup, so use `hf_spaces_search(author="X")`, `hf_models_search(author="X")`, or `hf_datasets_search(author="X")` rather than a global keyword-only search. -- For paper discovery, use `hf_papers_search(...)` for search, `hf_daily_papers(...)` for the curated daily feed, `hf_paper_info(...)` for exact metadata, and `hf_read_paper(...)` for markdown content. -- The main Hub-native join points on paper rows are `organization`, `submitted_by`, and `author_usernames`. Papers do not expose first-class model/dataset/space repo IDs. - For profile/detail/social questions about a user or org — bio, description, display name, website, GitHub, Twitter/X, LinkedIn, Bluesky, organizations, or pro status — use `hf_profile_summary(...)` first. - For join-style questions that need profile details for followers, following, members, likers, or other actor lists, first fetch a **bounded** actor list, filter locally on actor fields like `username` / `fullname`, then hydrate only the bounded matches with `hf_profile_summary(...)`. - Do **not** set the initial actor-list limit equal to the whole remaining call budget when each match needs a follow-up profile lookup; reserve budget for the profile-detail calls and return coverage if the hydration step is partial. @@ -63,45 +60,13 @@ result - Think like `huggingface_hub`: `search`, `filter`, `author`, repo-type-specific upstream params, then `fields`. - Push constraints upstream whenever a first-class helper argument exists. - `post_filter` is only for normalized row filters that cannot be pushed upstream. +- `num_params` is a first-class upstream model-search arg; use `num_params="min:6B,max:128B"` instead of `post_filter` when possible. - For created/updated date constraints, pair local `post_filter` with the matching sort (`created_at` or `last_modified`). Do **not** rely on date-only `post_filter` over an unsorted repo search window. - Keep `post_filter` simple: - exact match or `in` for returned fields like `runtime_stage` - - `gte` / `lte` for normalized numeric fields like `num_params`, `downloads`, and `likes` + - `gte` / `lte` for normalized numeric fields like `downloads` and `likes` - `gte` / `lte` also work for normalized ISO timestamp fields like `created_at` and `last_modified` -- `num_params` is one of the main valid reasons to use `post_filter` on model search today. -- Do **not** use `post_filter` for things that already have first-class upstream params like `author`, `pipeline_tag`, `dataset_name`, `language`, `models`, or `datasets`. - -## Common repo fields - -- `repo_id` -- `repo_type` -- `author` -- `likes` -- `downloads` -- `created_at` -- `last_modified` -- `num_params` -- `repo_url` -- model: `library_name`, `pipeline_tag` -- dataset: `description`, `paperswithcode_id` -- space: `sdk`, `models`, `datasets`, `subdomain` - -## Common collection fields - -- `collection_id` -- `title` -- `owner` -- `description` -- `last_updated` -- `item_count` -- use `hf_collections_search(owner="", ...)` for owner lookups - -## Common paper join points - -- `organization` -- `submitted_by` -- `author_usernames` -- `discussion_id` +- Do **not** use `post_filter` for things that already have first-class upstream params like `author`, `pipeline_tag`, `num_params` on model search, `dataset_name`, `language`, `models`, or `datasets`. Examples: @@ -113,9 +78,9 @@ result ```py result = await hf_models_search( pipeline_tag="text-generation", + num_params="min:20B,max:80B", sort="trending_score", limit=50, - post_filter={"num_params": {"gte": 20_000_000_000, "lte": 80_000_000_000}}, ) result ``` @@ -170,7 +135,7 @@ else: result ``` -Bounded join pattern: +Follower-profile join pattern: ```py followers_resp = await hf_user_graph( @@ -217,10 +182,81 @@ result = { result ``` -Use the same pattern for other bounded joins: -- actor list → filter locally → hydrate exact matches -- actor list → per-actor likes/details → aggregate under `results` -- preserve upstream helper `meta` under top-level `coverage` whenever partiality matters +Follower-likes aggregation pattern: + +```py +followers_resp = await hf_user_graph(relation="followers", limit=100, fields=["username"]) +followers = followers_resp.get("items") or [] +results = [] +for follower in followers: + username = follower.get("username") + if not username: + continue + likes_resp = await hf_user_likes( + username=username, + repo_types=["model"], + limit=20, + fields=["repo_id", "liked_at"], + ) + results.append( + { + "follower": username, + "liked_models": likes_resp.get("items") or [], + } + ) +coverage = { + "followers": followers_resp.get("meta") or {}, +} +result = {"results": results, "coverage": coverage} +result +``` + +Current-user pro-follower model-likes pattern: + +```py +followers_resp = await hf_user_graph( + relation="followers", + pro_only=True, + limit=100, + fields=["username"], +) +followers = followers_resp.get("items") or [] +remaining_calls = max(0, max_calls - 1) +results = {} +partial = ( + (followers_resp.get("meta") or {}).get("limit_boundary_hit") + or (followers_resp.get("meta") or {}).get("more_available") not in {False, None} +) +processed_followers = 0 +for follower in followers: + if remaining_calls <= 0: + partial = True + break + username = follower.get("username") + if not username: + continue + likes_resp = await hf_user_likes( + username=username, + repo_types=["model"], + limit=2, + fields=["repo_id", "repo_author", "liked_at"], + ) + remaining_calls -= 1 + likes_meta = likes_resp.get("meta") or {} + if likes_meta.get("limit_boundary_hit") or likes_meta.get("more_available") not in {False, None}: + partial = True + items = likes_resp.get("items") or [] + if items: + results[username] = items + processed_followers += 1 +coverage = { + "followers": followers_resp.get("meta") or {}, + "processed_followers": processed_followers, + "partial": partial, +} +result = {"results": results, "coverage": coverage} +result +``` ## Navigation graph @@ -232,10 +268,7 @@ Use the helper that matches the question type. - space search/list/discovery → `hf_spaces_search(...)` - cross-type repo search → `hf_repo_search(...)` - trending repos → `hf_trending(...)` -- Daily papers → `hf_daily_papers(...)` -- paper search → `hf_papers_search(...)` -- paper detail → `hf_paper_info(...)` -- paper markdown → `hf_read_paper(...)` +- daily papers → `hf_daily_papers(...)` - repo discussions → `hf_repo_discussions(...)` - specific discussion details → `hf_repo_discussion_details(...)` - users who liked one repo → `hf_repo_likers(...)` @@ -290,22 +323,16 @@ await hf_collection_items(collection_id: 'str', repo_types: 'list[str] | None' = await hf_collections_search(query: 'str | None' = None, owner: 'str | None' = None, limit: 'int' = 20, count_only: 'bool' = False, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' -await hf_daily_papers(date: 'str | None' = None, week: 'str | None' = None, month: 'str | None' = None, submitter: 'str | None' = None, sort: 'str | None' = None, p: 'int | None' = None, limit: 'int' = 20, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' +await hf_daily_papers(limit: 'int' = 20, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' -await hf_datasets_search(search: 'str | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, benchmark: 'str | bool | None' = None, dataset_name: 'str | None' = None, gated: 'bool | None' = None, language_creators: 'str | list[str] | None' = None, language: 'str | list[str] | None' = None, multilinguality: 'str | list[str] | None' = None, size_categories: 'str | list[str] | None' = None, task_categories: 'str | list[str] | None' = None, task_ids: 'str | list[str] | None' = None, sort: 'str | None' = None, limit: 'int' = 20, expand: 'list[str] | None' = None, full: 'bool | None' = None, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' +await hf_datasets_search(search: 'str | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, benchmark: 'str | bool | None' = None, dataset_name: 'str | None' = None, gated: 'bool | None' = None, language_creators: 'str | list[str] | None' = None, language: 'str | list[str] | None' = None, multilinguality: 'str | list[str] | None' = None, size_categories: 'str | list[str] | None' = None, task_categories: 'str | list[str] | None' = None, task_ids: 'str | list[str] | None' = None, sort: 'str | None' = None, limit: 'int' = 100, expand: 'list[str] | None' = None, full: 'bool | None' = None, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' -await hf_models_search(search: 'str | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, apps: 'str | list[str] | None' = None, gated: 'bool | None' = None, inference: 'str | None' = None, inference_provider: 'str | list[str] | None' = None, model_name: 'str | None' = None, trained_dataset: 'str | list[str] | None' = None, pipeline_tag: 'str | None' = None, emissions_thresholds: 'tuple[float, float] | None' = None, sort: 'str | None' = None, limit: 'int' = 20, expand: 'list[str] | None' = None, full: 'bool | None' = None, card_data: 'bool' = False, fetch_config: 'bool' = False, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' +await hf_models_search(search: 'str | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, apps: 'str | list[str] | None' = None, gated: 'bool | None' = None, inference: 'str | None' = None, inference_provider: 'str | list[str] | None' = None, model_name: 'str | None' = None, trained_dataset: 'str | list[str] | None' = None, pipeline_tag: 'str | None' = None, num_params: 'str | None' = None, emissions_thresholds: 'tuple[float, float] | None' = None, sort: 'str | None' = None, limit: 'int' = 100, expand: 'list[str] | None' = None, full: 'bool | None' = None, card_data: 'bool' = False, fetch_config: 'bool' = False, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' await hf_org_members(organization: 'str', limit: 'int | None' = None, scan_limit: 'int | None' = None, count_only: 'bool' = False, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' -await hf_paper_info(paper_id: 'str', fields: 'list[str] | None' = None) -> 'dict[str, Any]' - -await hf_papers_search(query: 'str', limit: 'int' = 20, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' - await hf_profile_summary(handle: 'str | None' = None, include: 'list[str] | None' = None, likes_limit: 'int' = 10, activity_limit: 'int' = 10) -> 'dict[str, Any]' -await hf_read_paper(paper_id: 'str') -> 'dict[str, Any]' - await hf_recent_activity(feed_type: 'str | None' = None, entity: 'str | None' = None, activity_types: 'list[str] | None' = None, repo_types: 'list[str] | None' = None, limit: 'int | None' = None, max_pages: 'int | None' = None, start_cursor: 'str | None' = None, count_only: 'bool' = False, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' await hf_repo_details(repo_id: 'str | None' = None, repo_ids: 'list[str] | None' = None, repo_type: 'str' = 'auto', fields: 'list[str] | None' = None) -> 'dict[str, Any]' @@ -316,11 +343,11 @@ await hf_repo_discussions(repo_type: 'str', repo_id: 'str', limit: 'int' = 20, f await hf_repo_likers(repo_id: 'str', repo_type: 'str', limit: 'int | None' = None, count_only: 'bool' = False, pro_only: 'bool | None' = None, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' -await hf_repo_search(search: 'str | None' = None, repo_type: 'str | None' = None, repo_types: 'list[str] | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, sort: 'str | None' = None, limit: 'int' = 20, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' +await hf_repo_search(search: 'str | None' = None, repo_type: 'str | None' = None, repo_types: 'list[str] | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, sort: 'str | None' = None, limit: 'int' = 100, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' await hf_runtime_capabilities(section: 'str | None' = None) -> 'dict[str, Any]' -await hf_spaces_search(search: 'str | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, datasets: 'str | list[str] | None' = None, models: 'str | list[str] | None' = None, linked: 'bool' = False, sort: 'str | None' = None, limit: 'int' = 20, expand: 'list[str] | None' = None, full: 'bool | None' = None, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' +await hf_spaces_search(search: 'str | None' = None, filter: 'str | list[str] | None' = None, author: 'str | None' = None, datasets: 'str | list[str] | None' = None, models: 'str | list[str] | None' = None, linked: 'bool' = False, sort: 'str | None' = None, limit: 'int' = 100, expand: 'list[str] | None' = None, full: 'bool | None' = None, fields: 'list[str] | None' = None, post_filter: 'dict[str, Any] | None' = None) -> 'dict[str, Any]' await hf_trending(repo_type: 'str' = 'model', limit: 'int' = 20, where: 'dict[str, Any] | None' = None, fields: 'list[str] | None' = None) -> 'dict[str, Any]' @@ -387,27 +414,24 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. ### hf_daily_papers - category: `curated_feed` -- backed_by: `HfApi.list_daily_papers` - returns: - envelope: `{ok, item, items, meta, error}` - - row_type: `paper` - - default_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` - - guaranteed_fields: `paper_id`, `title`, `published_at` - - optional_fields: `summary`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` -- supported_params: `date`, `week`, `month`, `submitter`, `sort`, `p`, `limit`, `where`, `fields` -- param_values: - - sort: `published_at`, `trending` + - row_type: `daily_paper` + - default_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_on_daily_at`, `authors`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `github_repo_url`, `github_stars`, `project_page_url`, `num_comments`, `is_author_participating`, `repo_id`, `rank` + - guaranteed_fields: `paper_id`, `title`, `published_at`, `rank` + - optional_fields: `summary`, `submitted_on_daily_at`, `authors`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `github_repo_url`, `github_stars`, `project_page_url`, `num_comments`, `is_author_participating`, `repo_id` +- supported_params: `limit`, `where`, `fields` - fields_contract: - - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` + - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_on_daily_at`, `authors`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `github_repo_url`, `github_stars`, `project_page_url`, `num_comments`, `is_author_participating`, `repo_id`, `rank` - canonical_only: `true` - where_contract: - - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` + - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_on_daily_at`, `authors`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `github_repo_url`, `github_stars`, `project_page_url`, `num_comments`, `is_author_participating`, `repo_id`, `rank` - supported_ops: `eq`, `in`, `contains`, `icontains`, `gte`, `lte` - normalized_only: `true` - limit_contract: - default_limit: `20` - max_limit: `500` -- notes: Curated daily papers feed backed by HfApi.list_daily_papers. Useful join points: organization, submitted_by, author_usernames, discussion_id. +- notes: Returns daily paper summary rows. repo_id is omitted unless the upstream payload provides it. ### hf_datasets_search @@ -430,7 +454,7 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - supported_ops: `eq`, `in`, `contains`, `icontains`, `gte`, `lte` - normalized_only: `true` - limit_contract: - - default_limit: `20` + - default_limit: `100` - max_limit: `5000` - notes: Thin dataset-search wrapper around the Hub list_datasets path. Prefer this over hf_repo_search for dataset-only queries. This is a one-shot selective search; if meta.limit_boundary_hit is true, more rows may exist and counts are not exact. @@ -444,7 +468,7 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - default_fields: `repo_id`, `repo_type`, `author`, `likes`, `downloads`, `trending_score`, `created_at`, `last_modified`, `pipeline_tag`, `num_params`, `repo_url`, `tags`, `library_name`, `description`, `paperswithcode_id`, `sdk`, `models`, `datasets`, `subdomain`, `runtime_stage`, `runtime` - guaranteed_fields: `repo_id`, `repo_type`, `author`, `repo_url` - optional_fields: `likes`, `downloads`, `trending_score`, `created_at`, `last_modified`, `pipeline_tag`, `num_params`, `tags`, `library_name`, `description`, `paperswithcode_id`, `sdk`, `models`, `datasets`, `subdomain`, `runtime_stage`, `runtime` -- supported_params: `search`, `filter`, `author`, `apps`, `gated`, `inference`, `inference_provider`, `model_name`, `trained_dataset`, `pipeline_tag`, `emissions_thresholds`, `sort`, `limit`, `expand`, `full`, `card_data`, `fetch_config`, `fields`, `post_filter` +- supported_params: `search`, `filter`, `author`, `apps`, `gated`, `inference`, `inference_provider`, `model_name`, `trained_dataset`, `pipeline_tag`, `num_params`, `emissions_thresholds`, `sort`, `limit`, `expand`, `full`, `card_data`, `fetch_config`, `fields`, `post_filter` - sort_values: `created_at`, `downloads`, `last_modified`, `likes`, `trending_score` - expand_values: `author`, `base_models`, `card_data`, `config`, `created_at`, `disabled`, `downloads`, `downloads_all_time`, `eval_results`, `gated`, `gguf`, `inference`, `inference_provider_mapping`, `last_modified`, `library_name`, `likes`, `mask_token`, `model_index`, `pipeline_tag`, `private`, `resource_group`, `safetensors`, `sha`, `siblings`, `spaces`, `tags`, `transformers_info`, `trending_score`, `widget_data`, `xet_enabled`, `gitaly_uid` - fields_contract: @@ -455,7 +479,7 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - supported_ops: `eq`, `in`, `contains`, `icontains`, `gte`, `lte` - normalized_only: `true` - limit_contract: - - default_limit: `20` + - default_limit: `100` - max_limit: `5000` - notes: Thin model-search wrapper around the Hub list_models path. Prefer this over hf_repo_search for model-only queries. This is a one-shot selective search; if meta.limit_boundary_hit is true, more rows may exist and counts are not exact. @@ -482,45 +506,6 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - scan_max: `10000` - notes: Returns organization member summary rows. -### hf_paper_info - -- category: `paper_detail` -- backed_by: `HfApi.paper_info` -- returns: - - envelope: `{ok, item, items, meta, error}` - - row_type: `paper` - - default_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` - - guaranteed_fields: `paper_id`, `title`, `published_at` - - optional_fields: `summary`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` -- supported_params: `paper_id`, `fields` -- fields_contract: - - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` - - canonical_only: `true` -- notes: Exact paper metadata helper backed by HfApi.paper_info. - -### hf_papers_search - -- category: `paper_search` -- backed_by: `HfApi.list_papers` -- returns: - - envelope: `{ok, item, items, meta, error}` - - row_type: `paper` - - default_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` - - guaranteed_fields: `paper_id`, `title`, `published_at` - - optional_fields: `summary`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` -- supported_params: `query`, `limit`, `where`, `fields` -- fields_contract: - - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` - - canonical_only: `true` -- where_contract: - - allowed_fields: `paper_id`, `title`, `summary`, `published_at`, `submitted_at`, `authors`, `author_usernames`, `organization`, `submitted_by`, `discussion_id`, `upvotes`, `source`, `comments`, `project_page`, `github_repo`, `github_stars`, `rank` - - supported_ops: `eq`, `in`, `contains`, `icontains`, `gte`, `lte` - - normalized_only: `true` -- limit_contract: - - default_limit: `20` - - max_limit: `500` -- notes: Paper search helper backed by HfApi.list_papers. Use organization, submitted_by, and author_usernames as the main Hub-native join points. - ### hf_profile_summary - category: `profile_summary` @@ -535,22 +520,6 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - include: `likes`, `activity` - notes: Profile summary helper. Aggregate counts like followers_count/following_count are in the base item. include=['likes', 'activity'] adds composed samples and extra upstream work; no other include values are supported. Overview-owned repo counts may differ slightly from visible public search/list results. -### hf_read_paper - -- category: `paper_markdown` -- backed_by: `HfApi.read_paper` -- returns: - - envelope: `{ok, item, items, meta, error}` - - row_type: `paper_content` - - default_fields: `paper_id`, `content` - - guaranteed_fields: `paper_id`, `content` - - optional_fields: [] -- supported_params: `paper_id` -- fields_contract: - - allowed_fields: `paper_id`, `content` - - canonical_only: `true` -- notes: Returns paper markdown content backed by HfApi.read_paper. - ### hf_recent_activity - category: `activity_feed` @@ -681,7 +650,7 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - supported_ops: `eq`, `in`, `contains`, `icontains`, `gte`, `lte` - normalized_only: `true` - limit_contract: - - default_limit: `20` + - default_limit: `100` - max_limit: `5000` - notes: Small generic repo-search helper. Prefer hf_models_search, hf_datasets_search, or hf_spaces_search for single-type queries; use hf_repo_search for intentionally cross-type search. This is a one-shot selective search; if meta.limit_boundary_hit is true, more rows may exist and counts are not exact. @@ -720,7 +689,7 @@ All helpers return the same envelope: `{ok, item, items, meta, error}`. - supported_ops: `eq`, `in`, `contains`, `icontains`, `gte`, `lte` - normalized_only: `true` - limit_contract: - - default_limit: `20` + - default_limit: `100` - max_limit: `5000` - notes: Thin space-search wrapper around the Hub list_spaces path. Prefer this over hf_repo_search for space-only queries. This is a one-shot selective search; if meta.limit_boundary_hit is true, more rows may exist and counts are not exact. diff --git a/hf-hub-query.md b/hf-hub-query.md index 46a218a027645aa9441ee06ef87f3300f16de3b4..49af2131cc978973653918251b5251cd22b654e3 100644 --- a/hf-hub-query.md +++ b/hf-hub-query.md @@ -1,12 +1,14 @@ --- type: agent name: hf_hub_query -model: gpt-oss +model: hf.openai/gpt-oss-120b:sambanova use_history: false default: true description: "Read-only Hugging Face Hub navigator for discovery, lookup, filtering, ranking, counts, field-constrained extraction, and relationship questions across users, orgs, models, datasets, spaces, collections, discussions, daily papers, recent activity, followers/following, likes, and likers. Good for structured raw outputs and compact results. Generated helper calls can explicitly bound limit, scan_limit, max_pages, and ranking_window for brevity or broader coverage, and the tool can also be asked about its supported helpers, canonical fields, defaults, and coverage behavior." shell: false skills: [] +#tool_hooks: +# after_llm_call: monty_api/llm_time_hook.py:display_llm_time function_tools: - entrypoint: tool_entrypoints.py:hf_hub_query_raw variant: code diff --git a/monty_api/__pycache__/__init__.cpython-313.pyc b/monty_api/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39512f92e121e50a5116f528216f948d19961ae4 Binary files /dev/null and b/monty_api/__pycache__/__init__.cpython-313.pyc differ diff --git a/monty_api/__pycache__/__init__.cpython-314.pyc b/monty_api/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..433f60430b3ae75a44880774cc88073890fd609a Binary files /dev/null and b/monty_api/__pycache__/__init__.cpython-314.pyc differ diff --git a/monty_api/__pycache__/aliases.cpython-313.pyc b/monty_api/__pycache__/aliases.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd1ae20d92321cec882a36fcc5ffd1c44862d4ea Binary files /dev/null and b/monty_api/__pycache__/aliases.cpython-313.pyc differ diff --git a/monty_api/__pycache__/aliases.cpython-314.pyc b/monty_api/__pycache__/aliases.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..683002c747b23d6f5f229969e3a8cc1769b448e9 Binary files /dev/null and b/monty_api/__pycache__/aliases.cpython-314.pyc differ diff --git a/monty_api/__pycache__/constants.cpython-313.pyc b/monty_api/__pycache__/constants.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..383f1e18932562011f23dd24d972dde0316344e3 Binary files /dev/null and b/monty_api/__pycache__/constants.cpython-313.pyc differ diff --git a/monty_api/__pycache__/constants.cpython-314.pyc b/monty_api/__pycache__/constants.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d2902498daf2525b66fb9b9592f8bcf12ff05dd Binary files /dev/null and b/monty_api/__pycache__/constants.cpython-314.pyc differ diff --git a/monty_api/__pycache__/context_types.cpython-313.pyc b/monty_api/__pycache__/context_types.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b917a0f9978bc536d1ab15ea2f80bf67981e7bfa Binary files /dev/null and b/monty_api/__pycache__/context_types.cpython-313.pyc differ diff --git a/monty_api/__pycache__/context_types.cpython-314.pyc b/monty_api/__pycache__/context_types.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11d63830dfdf87d8dbf734a3e2a507d62a4bcbc6 Binary files /dev/null and b/monty_api/__pycache__/context_types.cpython-314.pyc differ diff --git a/monty_api/__pycache__/helper_contracts.cpython-313.pyc b/monty_api/__pycache__/helper_contracts.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cae3cc5b617490af0aba6097e42b3bd9b24fbf0 Binary files /dev/null and b/monty_api/__pycache__/helper_contracts.cpython-313.pyc differ diff --git a/monty_api/__pycache__/helper_contracts.cpython-314.pyc b/monty_api/__pycache__/helper_contracts.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0438d877227d815586ab287d9d04a618fabca08 Binary files /dev/null and b/monty_api/__pycache__/helper_contracts.cpython-314.pyc differ diff --git a/monty_api/__pycache__/http_runtime.cpython-313.pyc b/monty_api/__pycache__/http_runtime.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b65540fdb94b76006e72ca52d2a8ec133204d4d1 Binary files /dev/null and b/monty_api/__pycache__/http_runtime.cpython-313.pyc differ diff --git a/monty_api/__pycache__/http_runtime.cpython-314.pyc b/monty_api/__pycache__/http_runtime.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e47cfcd67402509477fe596963cddd77164114a Binary files /dev/null and b/monty_api/__pycache__/http_runtime.cpython-314.pyc differ diff --git a/monty_api/__pycache__/llm_time_hook.cpython-314.pyc b/monty_api/__pycache__/llm_time_hook.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c0eb31d20a9776a675b5ed0fb6587522939972e0 Binary files /dev/null and b/monty_api/__pycache__/llm_time_hook.cpython-314.pyc differ diff --git a/monty_api/__pycache__/query_entrypoints.cpython-313.pyc b/monty_api/__pycache__/query_entrypoints.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa553a64537ca2bdc36d685ee54f2f3f75af7934 Binary files /dev/null and b/monty_api/__pycache__/query_entrypoints.cpython-313.pyc differ diff --git a/monty_api/__pycache__/query_entrypoints.cpython-314.pyc b/monty_api/__pycache__/query_entrypoints.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57d38dee85b919a6b9f818d0cdb593c2fa3048a5 Binary files /dev/null and b/monty_api/__pycache__/query_entrypoints.cpython-314.pyc differ diff --git a/monty_api/__pycache__/registry.cpython-313.pyc b/monty_api/__pycache__/registry.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..792b534e795aba52303e6f6a40a78ed3d6f7609d Binary files /dev/null and b/monty_api/__pycache__/registry.cpython-313.pyc differ diff --git a/monty_api/__pycache__/registry.cpython-314.pyc b/monty_api/__pycache__/registry.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b35f21b51d68a7a83a09504a00f2f82373b5a2cd Binary files /dev/null and b/monty_api/__pycache__/registry.cpython-314.pyc differ diff --git a/monty_api/__pycache__/runtime_context.cpython-313.pyc b/monty_api/__pycache__/runtime_context.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e74cd6113582703a1c3b9fe41774682c30f98de Binary files /dev/null and b/monty_api/__pycache__/runtime_context.cpython-313.pyc differ diff --git a/monty_api/__pycache__/runtime_context.cpython-314.pyc b/monty_api/__pycache__/runtime_context.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..270e5e1e162a3a433d32a97fbd70e4f47633e3da Binary files /dev/null and b/monty_api/__pycache__/runtime_context.cpython-314.pyc differ diff --git a/monty_api/__pycache__/runtime_envelopes.cpython-313.pyc b/monty_api/__pycache__/runtime_envelopes.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d703184b54e5a51307766c5e08d78a8fbff70646 Binary files /dev/null and b/monty_api/__pycache__/runtime_envelopes.cpython-313.pyc differ diff --git a/monty_api/__pycache__/runtime_envelopes.cpython-314.pyc b/monty_api/__pycache__/runtime_envelopes.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cd0651f43e24f28984abb8eaba717c3cc7ac5de Binary files /dev/null and b/monty_api/__pycache__/runtime_envelopes.cpython-314.pyc differ diff --git a/monty_api/__pycache__/runtime_filtering.cpython-313.pyc b/monty_api/__pycache__/runtime_filtering.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82372e86c34f14c0a2a9546d01890abb68e04e4e Binary files /dev/null and b/monty_api/__pycache__/runtime_filtering.cpython-313.pyc differ diff --git a/monty_api/__pycache__/runtime_filtering.cpython-314.pyc b/monty_api/__pycache__/runtime_filtering.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a977f7b0c9908f781e4f69c6fbb2ded86b329e5a Binary files /dev/null and b/monty_api/__pycache__/runtime_filtering.cpython-314.pyc differ diff --git a/monty_api/__pycache__/tool_entrypoints.cpython-313.pyc b/monty_api/__pycache__/tool_entrypoints.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92b533ffab1357b4d043910d94e8367b14338ff3 Binary files /dev/null and b/monty_api/__pycache__/tool_entrypoints.cpython-313.pyc differ diff --git a/monty_api/__pycache__/tool_entrypoints.cpython-314.pyc b/monty_api/__pycache__/tool_entrypoints.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de0e4ee7da275cd33bb4e7322268b32999c2b403 Binary files /dev/null and b/monty_api/__pycache__/tool_entrypoints.cpython-314.pyc differ diff --git a/monty_api/__pycache__/validation.cpython-313.pyc b/monty_api/__pycache__/validation.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de3f1a8b35d78590b5b44cc0b9f29ad0cd449915 Binary files /dev/null and b/monty_api/__pycache__/validation.cpython-313.pyc differ diff --git a/monty_api/__pycache__/validation.cpython-314.pyc b/monty_api/__pycache__/validation.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8af2f06f189266aab9755e47b2fc29966ae1223f Binary files /dev/null and b/monty_api/__pycache__/validation.cpython-314.pyc differ diff --git a/monty_api/constants.py b/monty_api/constants.py index 6d6fade0f949365085034c475ac1bfad69aa29b6..91c152907cc1c1c5e2a1f65d23bc8da3740b2f5d 100644 --- a/monty_api/constants.py +++ b/monty_api/constants.py @@ -183,24 +183,22 @@ COLLECTION_CANONICAL_FIELDS: tuple[str, ...] = ( "item_count", ) -PAPER_CANONICAL_FIELDS: tuple[str, ...] = ( +DAILY_PAPER_CANONICAL_FIELDS: tuple[str, ...] = ( "paper_id", "title", "summary", "published_at", - "submitted_at", + "submitted_on_daily_at", "authors", - "author_usernames", "organization", "submitted_by", "discussion_id", "upvotes", - "source", - "comments", - "project_page", - "github_repo", + "github_repo_url", "github_stars", + "project_page_url", + "num_comments", + "is_author_participating", + "repo_id", "rank", ) - -PAPER_CONTENT_FIELDS: tuple[str, ...] = ("paper_id", "content") diff --git a/monty_api/helper_contracts.py b/monty_api/helper_contracts.py index a88c910c9ae73afb5f77b5e06478ecd84c43e884..3c3ac77a9713d1a50ec55b084554f87df905a79e 100644 --- a/monty_api/helper_contracts.py +++ b/monty_api/helper_contracts.py @@ -16,10 +16,9 @@ from .constants import ( ACTIVITY_CANONICAL_FIELDS, ACTOR_CANONICAL_FIELDS, COLLECTION_CANONICAL_FIELDS, + DAILY_PAPER_CANONICAL_FIELDS, DISCUSSION_CANONICAL_FIELDS, DISCUSSION_DETAIL_CANONICAL_FIELDS, - PAPER_CANONICAL_FIELDS, - PAPER_CONTENT_FIELDS, PROFILE_CANONICAL_FIELDS, REPO_CANONICAL_FIELDS, USER_CANONICAL_FIELDS, @@ -77,10 +76,9 @@ FIELD_GROUPS: dict[str, list[str]] = { "activity": list(ACTIVITY_CANONICAL_FIELDS), "actor": list(ACTOR_CANONICAL_FIELDS), "collection": list(COLLECTION_CANONICAL_FIELDS), + "daily_paper": list(DAILY_PAPER_CANONICAL_FIELDS), "discussion": list(DISCUSSION_CANONICAL_FIELDS), "discussion_detail": list(DISCUSSION_DETAIL_CANONICAL_FIELDS), - "paper": list(PAPER_CANONICAL_FIELDS), - "paper_content": list(PAPER_CONTENT_FIELDS), "profile": list(PROFILE_CANONICAL_FIELDS), "repo": list(REPO_CANONICAL_FIELDS), "trending_repo": list(TRENDING_CANONICAL_FIELDS), @@ -111,12 +109,10 @@ HELPER_CONTRACT_SPECS: dict[str, dict[str, Any]] = { }, "hf_daily_papers": { "category": "curated_feed", - "row_type": "paper", - "fields_group": "paper", + "row_type": "daily_paper", + "fields_group": "daily_paper", "filter_param": "where", - "filter_group": "paper", - "param_values": {"sort": ["published_at", "trending"]}, - "backed_by": "HfApi.list_daily_papers", + "filter_group": "daily_paper", }, "hf_datasets_search": { "category": "wrapped_hf_repo_search", @@ -146,20 +142,6 @@ HELPER_CONTRACT_SPECS: dict[str, dict[str, Any]] = { "row_type": "profile", "param_values": {"include": ["likes", "activity"]}, }, - "hf_paper_info": { - "category": "paper_detail", - "row_type": "paper", - "fields_group": "paper", - "backed_by": "HfApi.paper_info", - }, - "hf_papers_search": { - "category": "paper_search", - "row_type": "paper", - "fields_group": "paper", - "filter_param": "where", - "filter_group": "paper", - "backed_by": "HfApi.list_papers", - }, "hf_recent_activity": { "category": "activity_feed", "row_type": "activity", @@ -207,12 +189,6 @@ HELPER_CONTRACT_SPECS: dict[str, dict[str, Any]] = { "row_type": "runtime_capability", "param_values": {"section": list(RUNTIME_CAPABILITY_SECTION_VALUES)}, }, - "hf_read_paper": { - "category": "paper_markdown", - "row_type": "paper_content", - "fields_group": "paper_content", - "backed_by": "HfApi.read_paper", - }, "hf_spaces_search": { "category": "wrapped_hf_repo_search", "row_type": "repo", @@ -420,9 +396,6 @@ def build_helper_contracts( param_values = _param_values_for_helper(helper_name) if param_values is not None: contract["param_values"] = param_values - backed_by = spec.get("backed_by") - if isinstance(backed_by, str): - contract["backed_by"] = backed_by upstream_repo_type = spec.get("upstream_repo_type") if isinstance(upstream_repo_type, str): diff --git a/monty_api/helpers/__init__.py b/monty_api/helpers/__init__.py index 2bc18dc35db4c712b101c5c95d2983ebb569748f..88eb47e0d95c71f80c55276d40d7ce413b8e07d3 100644 --- a/monty_api/helpers/__init__.py +++ b/monty_api/helpers/__init__.py @@ -1,7 +1,6 @@ from .activity import register_activity_helpers from .collections import register_collection_helpers from .introspection import register_introspection_helpers -from .papers import register_paper_helpers from .profiles import register_profile_helpers from .repos import register_repo_helpers @@ -9,7 +8,6 @@ __all__ = [ "register_activity_helpers", "register_collection_helpers", "register_introspection_helpers", - "register_paper_helpers", "register_profile_helpers", "register_repo_helpers", ] diff --git a/monty_api/helpers/__pycache__/__init__.cpython-313.pyc b/monty_api/helpers/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b7fb4c6512c8de74217a37aeb7dfbd2d9201b33 Binary files /dev/null and b/monty_api/helpers/__pycache__/__init__.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/__init__.cpython-314.pyc b/monty_api/helpers/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04fa78e132ccddfeb5a71d7715b4d17f67ebe234 Binary files /dev/null and b/monty_api/helpers/__pycache__/__init__.cpython-314.pyc differ diff --git a/monty_api/helpers/__pycache__/activity.cpython-313.pyc b/monty_api/helpers/__pycache__/activity.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a99ea3fa5d25bc4726660f3b265881ddfd6106ec Binary files /dev/null and b/monty_api/helpers/__pycache__/activity.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/activity.cpython-314.pyc b/monty_api/helpers/__pycache__/activity.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06eda356bc1abf6a5a8281a285368450925a1dbc Binary files /dev/null and b/monty_api/helpers/__pycache__/activity.cpython-314.pyc differ diff --git a/monty_api/helpers/__pycache__/collections.cpython-313.pyc b/monty_api/helpers/__pycache__/collections.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c1b08096a5c7ca789fa23b74068cd83a4d8d57e Binary files /dev/null and b/monty_api/helpers/__pycache__/collections.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/collections.cpython-314.pyc b/monty_api/helpers/__pycache__/collections.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8084cff8a506017a9c135a11ef663d0c5ae44cde Binary files /dev/null and b/monty_api/helpers/__pycache__/collections.cpython-314.pyc differ diff --git a/monty_api/helpers/__pycache__/common.cpython-313.pyc b/monty_api/helpers/__pycache__/common.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe7a43e5b99e30fba0b37cecea03fdae16db6eea Binary files /dev/null and b/monty_api/helpers/__pycache__/common.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/common.cpython-314.pyc b/monty_api/helpers/__pycache__/common.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75718b2a613b0cfc0cf0b59b033c08f45f5a4b10 Binary files /dev/null and b/monty_api/helpers/__pycache__/common.cpython-314.pyc differ diff --git a/monty_api/helpers/__pycache__/introspection.cpython-313.pyc b/monty_api/helpers/__pycache__/introspection.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7fac1a438d65f61f68d7a2fcd345280b2583545 Binary files /dev/null and b/monty_api/helpers/__pycache__/introspection.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/introspection.cpython-314.pyc b/monty_api/helpers/__pycache__/introspection.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d29727f9ffd4cf6a3c00d85c48a3217dc81ead0 Binary files /dev/null and b/monty_api/helpers/__pycache__/introspection.cpython-314.pyc differ diff --git a/monty_api/helpers/__pycache__/profiles.cpython-313.pyc b/monty_api/helpers/__pycache__/profiles.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39c6c94864393c18cb06a97b7dad8e92e62e922e Binary files /dev/null and b/monty_api/helpers/__pycache__/profiles.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/profiles.cpython-314.pyc b/monty_api/helpers/__pycache__/profiles.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e464de48ef0802df560a02a8c0d80877d7a97e1 Binary files /dev/null and b/monty_api/helpers/__pycache__/profiles.cpython-314.pyc differ diff --git a/monty_api/helpers/__pycache__/repos.cpython-313.pyc b/monty_api/helpers/__pycache__/repos.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12073a1e5a7bae1c0c9388e543c5a1a0b09748a5 Binary files /dev/null and b/monty_api/helpers/__pycache__/repos.cpython-313.pyc differ diff --git a/monty_api/helpers/__pycache__/repos.cpython-314.pyc b/monty_api/helpers/__pycache__/repos.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38b01a9d4d15d75d985984cb0592122561ece6d9 Binary files /dev/null and b/monty_api/helpers/__pycache__/repos.cpython-314.pyc differ diff --git a/monty_api/helpers/introspection.py b/monty_api/helpers/introspection.py index 1559825cd0d1a7199701844b0af3865c320dc9a6..c3c51e1c263bab059e05ac6f69937bbdcb8b99aa 100644 --- a/monty_api/helpers/introspection.py +++ b/monty_api/helpers/introspection.py @@ -10,6 +10,7 @@ from ..constants import ( ACTIVITY_CANONICAL_FIELDS, ACTOR_CANONICAL_FIELDS, COLLECTION_CANONICAL_FIELDS, + DAILY_PAPER_CANONICAL_FIELDS, DISCUSSION_CANONICAL_FIELDS, DISCUSSION_DETAIL_CANONICAL_FIELDS, DEFAULT_MAX_CALLS, @@ -18,8 +19,6 @@ from ..constants import ( LIKES_SCAN_LIMIT_CAP, MAX_CALLS_LIMIT, OUTPUT_ITEMS_TRUNCATION_LIMIT, - PAPER_CANONICAL_FIELDS, - PAPER_CONTENT_FIELDS, PROFILE_CANONICAL_FIELDS, RECENT_ACTIVITY_SCAN_MAX_PAGES, REPO_CANONICAL_FIELDS, @@ -141,8 +140,7 @@ async def hf_runtime_capabilities( "user_likes": list(USER_LIKES_CANONICAL_FIELDS), "activity": list(ACTIVITY_CANONICAL_FIELDS), "collection": list(COLLECTION_CANONICAL_FIELDS), - "paper": list(PAPER_CANONICAL_FIELDS), - "paper_content": list(PAPER_CONTENT_FIELDS), + "daily_paper": list(DAILY_PAPER_CANONICAL_FIELDS), "discussion": list(DISCUSSION_CANONICAL_FIELDS), "discussion_detail": list(DISCUSSION_DETAIL_CANONICAL_FIELDS), }, diff --git a/monty_api/helpers/profiles.py b/monty_api/helpers/profiles.py index c3b06be84b3adde59836a237e5b43e0d1e9dd0b0..509cfb3cf10398612630dd2824e01269e5344b5b 100644 --- a/monty_api/helpers/profiles.py +++ b/monty_api/helpers/profiles.py @@ -338,8 +338,8 @@ async def hf_org_members( ) sample_complete = ( exact_count - and total_matched <= applied_limit - and (not count_only or total_matched == 0) + and len(normalized) <= applied_limit + and (not count_only or len(normalized) == 0) ) more_available = ctx._derive_more_available( sample_complete=sample_complete, @@ -372,18 +372,13 @@ async def hf_org_members( "organization": org, }, limit_plan=limit_plan, - matched_count=total_matched, + matched_count=len(normalized), returned_count=len(items), exact_count=exact_count, count_only=count_only, sample_complete=sample_complete, more_available=more_available, - scan_limit_hit=scan_limit_hit - or ( - overview_total is not None - and overview_total > observed_total - and observed_total >= scan_lim - ), + scan_limit_hit=scan_limit_hit, ) return ctx._helper_success( start_calls=start_calls, source=endpoint, items=items, meta=meta @@ -578,8 +573,8 @@ async def _user_graph_helper( ) sample_complete = ( exact_count - and total_matched <= applied_limit - and (not count_only or total_matched == 0) + and len(normalized) <= applied_limit + and (not count_only or len(normalized) == 0) ) more_available = ctx._derive_more_available( sample_complete=sample_complete, @@ -622,18 +617,13 @@ async def _user_graph_helper( "organization": u if entity_type == "organization" else None, }, limit_plan=limit_plan, - matched_count=total_matched, + matched_count=len(normalized), returned_count=len(items), exact_count=exact_count, count_only=count_only, sample_complete=sample_complete, more_available=more_available, - scan_limit_hit=scan_limit_hit - or ( - overview_total is not None - and overview_total > observed_total - and observed_total >= scan_lim - ), + scan_limit_hit=scan_limit_hit, ) return ctx._helper_success( start_calls=start_calls, source=endpoint, items=items, meta=meta diff --git a/monty_api/helpers/repos.py b/monty_api/helpers/repos.py index 8faf96a94af82b6edf0ab58b875645d5e969828b..ef32dde232ae406101e899f073505e54b5539791 100644 --- a/monty_api/helpers/repos.py +++ b/monty_api/helpers/repos.py @@ -7,6 +7,7 @@ from ..context_types import HelperRuntimeContext from ..helper_contracts import repo_expand_alias_map from ..constants import ( ACTOR_CANONICAL_FIELDS, + DAILY_PAPER_CANONICAL_FIELDS, EXHAUSTIVE_HELPER_RETURN_HARD_CAP, LIKES_ENRICHMENT_MAX_REPOS, LIKES_RANKING_WINDOW_DEFAULT, @@ -122,6 +123,9 @@ def _build_repo_search_extra_args( if value: normalized["cardData"] = True continue + if key in {"num_params", "num_parameters"}: + normalized["num_parameters"] = value + continue if key in {"fetch_config", "linked"}: if value: normalized[key] = True @@ -179,7 +183,7 @@ async def _run_repo_search( extra_args_by_type: dict[str, dict[str, Any]] | None = None, ) -> dict[str, Any]: start_calls = ctx.call_count["n"] - default_limit = ctx._policy_int(helper_name, "default_limit", 20) + default_limit = ctx._policy_int(helper_name, "default_limit", 100) max_limit = ctx._policy_int( helper_name, "max_limit", SELECTIVE_ENDPOINT_RETURN_HARD_CAP ) @@ -339,9 +343,10 @@ async def hf_models_search( model_name: str | None = None, trained_dataset: str | list[str] | None = None, pipeline_tag: str | None = None, + num_params: str | None = None, emissions_thresholds: tuple[float, float] | None = None, sort: str | None = None, - limit: int = 20, + limit: int = 100, expand: list[str] | None = None, full: bool | None = None, card_data: bool = False, @@ -369,6 +374,7 @@ async def hf_models_search( "model_name": model_name, "trained_dataset": trained_dataset, "pipeline_tag": pipeline_tag, + "num_params": num_params, "emissions_thresholds": emissions_thresholds, "expand": expand, "full": full, @@ -394,7 +400,7 @@ async def hf_datasets_search( task_categories: str | list[str] | None = None, task_ids: str | list[str] | None = None, sort: str | None = None, - limit: int = 20, + limit: int = 100, expand: list[str] | None = None, full: bool | None = None, fields: list[str] | None = None, @@ -438,7 +444,7 @@ async def hf_spaces_search( models: str | list[str] | None = None, linked: bool = False, sort: str | None = None, - limit: int = 20, + limit: int = 100, expand: list[str] | None = None, full: bool | None = None, fields: list[str] | None = None, @@ -475,7 +481,7 @@ async def hf_repo_search( filter: str | list[str] | None = None, author: str | None = None, sort: str | None = None, - limit: int = 20, + limit: int = 100, fields: list[str] | None = None, post_filter: dict[str, Any] | None = None, ) -> dict[str, Any]: @@ -1286,6 +1292,62 @@ async def hf_trending( ) +async def hf_daily_papers( + ctx: HelperRuntimeContext, + limit: int = 20, + where: dict[str, Any] | None = None, + fields: list[str] | None = None, +) -> dict[str, Any]: + start_calls = ctx.call_count["n"] + default_limit = ctx._policy_int("hf_daily_papers", "default_limit", 20) + max_limit = ctx._policy_int( + "hf_daily_papers", "max_limit", OUTPUT_ITEMS_TRUNCATION_LIMIT + ) + lim = ctx._clamp_int(limit, default=default_limit, minimum=1, maximum=max_limit) + resp = ctx._host_raw_call("/api/daily_papers", params={"limit": lim}) + if not resp.get("ok"): + return ctx._helper_error( + start_calls=start_calls, + source="/api/daily_papers", + error=resp.get("error") or "daily papers fetch failed", + ) + payload = resp.get("data") if isinstance(resp.get("data"), list) else [] + items: list[dict[str, Any]] = [] + for idx, row in enumerate(payload[:lim], start=1): + if not isinstance(row, dict): + continue + items.append(ctx._normalize_daily_paper_row(row, rank=idx)) + try: + items = ctx._apply_where( + items, where, allowed_fields=DAILY_PAPER_CANONICAL_FIELDS + ) + except ValueError as exc: + return ctx._helper_error( + start_calls=start_calls, + source="/api/daily_papers", + error=exc, + ) + matched = len(items) + try: + items = ctx._project_daily_paper_items(items[:lim], fields) + except ValueError as exc: + return ctx._helper_error( + start_calls=start_calls, + source="/api/daily_papers", + error=exc, + ) + return ctx._helper_success( + start_calls=start_calls, + source="/api/daily_papers", + items=items, + limit=lim, + scanned=len(payload), + matched=matched, + returned=len(items), + ordered_ranking=True, + ) + + def register_repo_helpers(ctx: HelperRuntimeContext) -> dict[str, Callable[..., Any]]: return { "hf_models_search": partial(hf_models_search, ctx), @@ -1298,4 +1360,5 @@ def register_repo_helpers(ctx: HelperRuntimeContext) -> dict[str, Callable[..., "hf_repo_discussion_details": partial(hf_repo_discussion_details, ctx), "hf_repo_details": partial(hf_repo_details, ctx), "hf_trending": partial(hf_trending, ctx), + "hf_daily_papers": partial(hf_daily_papers, ctx), } diff --git a/monty_api/http_runtime.py b/monty_api/http_runtime.py index 451525bbd159d1176f3e8f133489863f6a63b587..5797ad34599857661bc621999249d1af8af8487c 100644 --- a/monty_api/http_runtime.py +++ b/monty_api/http_runtime.py @@ -429,6 +429,47 @@ def _normalize_trending_row( return row +def _normalize_daily_paper_row( + row: dict[str, Any], rank: int | None = None +) -> dict[str, Any]: + paper = row.get("paper") if isinstance(row.get("paper"), dict) else {} + org = ( + row.get("organization") + if isinstance(row.get("organization"), dict) + else paper.get("organization") + ) + organization = None + if isinstance(org, dict): + organization = org.get("name") or org.get("fullname") + + item = { + "paper_id": paper.get("id"), + "title": row.get("title") or paper.get("title"), + "summary": row.get("summary") + or paper.get("summary") + or paper.get("ai_summary"), + "published_at": row.get("publishedAt") or paper.get("publishedAt"), + "submitted_on_daily_at": paper.get("submittedOnDailyAt"), + "authors": _extract_author_names(paper.get("authors")), + "organization": organization, + "submitted_by": _extract_profile_name( + row.get("submittedBy") or paper.get("submittedOnDailyBy") + ), + "discussion_id": paper.get("discussionId"), + "upvotes": _as_int(paper.get("upvotes")), + "github_repo_url": paper.get("githubRepo"), + "github_stars": _as_int(paper.get("githubStars")), + "project_page_url": paper.get("projectPage"), + "num_comments": _as_int(row.get("numComments")), + "is_author_participating": row.get("isAuthorParticipating") + if isinstance(row.get("isAuthorParticipating"), bool) + else None, + "repo_id": row.get("repo_id") or paper.get("repo_id"), + "rank": rank, + } + return item + + def _normalize_collection_repo_item(row: dict[str, Any]) -> dict[str, Any] | None: repo_id = row.get("id") or row.get("repoId") or row.get("repo_id") if not isinstance(repo_id, str) or not repo_id: diff --git a/monty_api/llm_time_hook.py b/monty_api/llm_time_hook.py new file mode 100644 index 0000000000000000000000000000000000000000..696786290b2e52f0da1ae06fc40a2dfa7612b68a --- /dev/null +++ b/monty_api/llm_time_hook.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +import json +from typing import TYPE_CHECKING + +from fast_agent.constants import FAST_AGENT_TIMING +from fast_agent.hooks import show_hook_message +from fast_agent.mcp.helpers.content_helpers import get_text + +if TYPE_CHECKING: + from fast_agent.hooks import HookContext + + +def _timing_payload(ctx: "HookContext") -> dict[str, object] | None: + channels = ctx.message.channels or {} + timing_blocks = channels.get(FAST_AGENT_TIMING, []) + if not timing_blocks: + return None + + payload_text = get_text(timing_blocks[0]) + if not payload_text: + return None + + try: + payload = json.loads(payload_text) + except json.JSONDecodeError: + return None + + return payload if isinstance(payload, dict) else None + + +def _coerce_float(value: object) -> float | None: + if isinstance(value, bool): + return None + if isinstance(value, int | float): + return float(value) + return None + + +def _format_duration_ms(duration_ms: float) -> str: + if duration_ms >= 1000: + return f"{duration_ms / 1000:.2f}s" + return f"{duration_ms:.0f}ms" + + +async def display_llm_time(ctx: "HookContext") -> None: + payload = _timing_payload(ctx) + if payload is None: + return + + duration_ms = _coerce_float(payload.get("duration_ms")) + if duration_ms is None: + return + + show_hook_message( + ctx, + _format_duration_ms(duration_ms), + hook_name="llm_time", + hook_kind="tool", + ) diff --git a/monty_api/query_entrypoints.py b/monty_api/query_entrypoints.py index 18fb6a0172850c6dbdaa7d6a1fd8bd1109235780..2a459245753bcac10eb9b16be1ea1ccb0b19f8ac 100644 --- a/monty_api/query_entrypoints.py +++ b/monty_api/query_entrypoints.py @@ -7,7 +7,6 @@ import json import os import sys import time -import warnings from typing import Any, Callable from .constants import ( @@ -37,25 +36,6 @@ class MontyExecutionError(RuntimeError): self.trace = trace -_PYDANTIC_MONTY_ISCOROUTINE_DEPRECATION = ( - r"'inspect\.iscoroutinefunction' is deprecated and slated for removal in Python 3\.16" -) - - -def _install_known_runtime_warning_filters( - *, version_info: tuple[int, ...] | None = None -) -> None: - active_version = version_info or sys.version_info - if tuple(active_version) < (3, 14): - return - warnings.filterwarnings( - "ignore", - message=_PYDANTIC_MONTY_ISCOROUTINE_DEPRECATION, - category=DeprecationWarning, - module=r"pydantic_monty(\..*)?", - ) - - def _query_debug_enabled() -> bool: value = os.environ.get("MONTY_DEBUG_QUERY", "") return value.strip().lower() in {"1", "true", "yes", "on"} @@ -105,28 +85,6 @@ def _introspect_helper_signatures() -> dict[str, set[str]]: return signatures -async def _run_monty_program( - monty: Any, - *, - inputs: dict[str, Any], - external_functions: dict[str, Callable[..., Any]], - limits: Any, -) -> Any: - run_async = getattr(monty, "run_async", None) - if callable(run_async): - return await run_async( - inputs=inputs, - external_functions=external_functions, - limits=limits, - ) - - raise RuntimeError( - "Unsupported pydantic_monty runtime: this fast-agent Monty wrapper " - "requires Monty.run_async(...). Installed pydantic-monty appears too old; " - "use pydantic-monty>=0.0.10." - ) - - async def _run_with_monty( *, code: str, @@ -141,7 +99,6 @@ async def _run_with_monty( f"timeout_sec={timeout_sec}", f"strict_mode={strict_mode}", ) - _install_known_runtime_warning_filters() try: import pydantic_monty except Exception as e: @@ -197,7 +154,7 @@ async def _run_with_monty( try: _debug_log("run_monty:invoke") - result = await _run_monty_program( + result = await pydantic_monty.run_monty_async( m, inputs={"query": query or "", "max_calls": max_calls}, external_functions={ @@ -255,14 +212,6 @@ async def _run_with_monty( ) if not any(step.get("ok") is True for step in env.trace): - latest_helper_error = env.latest_helper_error_box.get("value") - if latest_helper_error is not None: - return { - "output": _truncate_result_payload(latest_helper_error), - "api_calls": env.call_count["n"], - "trace": env.trace, - "limit_summaries": env.limit_summaries, - } if ( isinstance(result, dict) and result.get("ok") is False diff --git a/monty_api/registry.py b/monty_api/registry.py index eb5e72b82d8ad69c3474d9dcd94a36f4d6b82577..aa8fe31b7f03712e9a93f21a46d23d4f226fe086 100644 --- a/monty_api/registry.py +++ b/monty_api/registry.py @@ -7,6 +7,7 @@ from .constants import ( ACTIVITY_CANONICAL_FIELDS, ACTOR_CANONICAL_FIELDS, COLLECTION_CANONICAL_FIELDS, + DAILY_PAPER_CANONICAL_FIELDS, DISCUSSION_CANONICAL_FIELDS, DISCUSSION_DETAIL_CANONICAL_FIELDS, GRAPH_SCAN_LIMIT_CAP, @@ -15,8 +16,6 @@ from .constants import ( LIKES_SCAN_LIMIT_CAP, OUTPUT_ITEMS_TRUNCATION_LIMIT, PROFILE_CANONICAL_FIELDS, - PAPER_CANONICAL_FIELDS, - PAPER_CONTENT_FIELDS, RECENT_ACTIVITY_PAGE_SIZE, RECENT_ACTIVITY_SCAN_MAX_PAGES, REPO_CANONICAL_FIELDS, @@ -63,6 +62,7 @@ REPO_SEARCH_EXTRA_ARGS: dict[str, set[str]] = { "inference", "inference_provider", "model_name", + "num_parameters", "pipeline_tag", "trained_dataset", }, @@ -231,13 +231,12 @@ TRENDING_OPTIONAL_FIELDS = [ for field in TRENDING_DEFAULT_FIELDS if field not in {"repo_id", "repo_type", "author", "repo_url", "trending_rank"} ] -PAPER_DEFAULT_FIELDS = list(PAPER_CANONICAL_FIELDS) -PAPER_OPTIONAL_FIELDS = [ +DAILY_PAPER_DEFAULT_FIELDS = list(DAILY_PAPER_CANONICAL_FIELDS) +DAILY_PAPER_OPTIONAL_FIELDS = [ field - for field in PAPER_CANONICAL_FIELDS - if field not in {"paper_id", "title", "published_at"} + for field in DAILY_PAPER_CANONICAL_FIELDS + if field not in {"paper_id", "title", "published_at", "rank"} ] -PAPER_CONTENT_DEFAULT_FIELDS = list(PAPER_CONTENT_FIELDS) COLLECTION_DEFAULT_FIELDS = list(COLLECTION_CANONICAL_FIELDS) COLLECTION_OPTIONAL_FIELDS = [ field @@ -352,7 +351,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { default_fields=REPO_SUMMARY_FIELDS, guaranteed_fields=["repo_id", "repo_type", "author", "repo_url"], optional_fields=REPO_SUMMARY_OPTIONAL_FIELDS, - default_limit=20, + default_limit=100, max_limit=5_000, notes=( "Thin model-search wrapper around the Hub list_models path. Prefer this " @@ -361,7 +360,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { "are not exact." ), ), - pagination={"default_limit": 20, "max_limit": 5_000}, + pagination={"default_limit": 100, "max_limit": 5_000}, ), "hf_datasets_search": _config( "hf_datasets_search", @@ -370,7 +369,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { default_fields=REPO_SUMMARY_FIELDS, guaranteed_fields=["repo_id", "repo_type", "author", "repo_url"], optional_fields=REPO_SUMMARY_OPTIONAL_FIELDS, - default_limit=20, + default_limit=100, max_limit=5_000, notes=( "Thin dataset-search wrapper around the Hub list_datasets path. Prefer " @@ -379,7 +378,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { "and counts are not exact." ), ), - pagination={"default_limit": 20, "max_limit": 5_000}, + pagination={"default_limit": 100, "max_limit": 5_000}, ), "hf_spaces_search": _config( "hf_spaces_search", @@ -388,7 +387,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { default_fields=REPO_SUMMARY_FIELDS, guaranteed_fields=["repo_id", "repo_type", "author", "repo_url"], optional_fields=REPO_SUMMARY_OPTIONAL_FIELDS, - default_limit=20, + default_limit=100, max_limit=5_000, notes=( "Thin space-search wrapper around the Hub list_spaces path. Prefer this " @@ -397,7 +396,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { "are not exact." ), ), - pagination={"default_limit": 20, "max_limit": 5_000}, + pagination={"default_limit": 100, "max_limit": 5_000}, ), "hf_repo_search": _config( "hf_repo_search", @@ -406,7 +405,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { default_fields=REPO_SUMMARY_FIELDS, guaranteed_fields=["repo_id", "repo_type", "author", "repo_url"], optional_fields=REPO_SUMMARY_OPTIONAL_FIELDS, - default_limit=20, + default_limit=100, max_limit=5_000, notes=( "Small generic repo-search helper. Prefer hf_models_search, " @@ -416,7 +415,7 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { "and counts are not exact." ), ), - pagination={"default_limit": 20, "max_limit": 5_000}, + pagination={"default_limit": 100, "max_limit": 5_000}, ), "hf_user_graph": _config( "hf_user_graph", @@ -565,48 +564,15 @@ HELPER_CONFIGS: dict[str, HelperConfig] = { "hf_daily_papers", endpoint_patterns=(r"^/api/daily_papers$",), default_metadata=_metadata( - default_fields=PAPER_DEFAULT_FIELDS, - guaranteed_fields=["paper_id", "title", "published_at"], - optional_fields=PAPER_OPTIONAL_FIELDS, + default_fields=DAILY_PAPER_DEFAULT_FIELDS, + guaranteed_fields=["paper_id", "title", "published_at", "rank"], + optional_fields=DAILY_PAPER_OPTIONAL_FIELDS, default_limit=20, max_limit=OUTPUT_ITEMS_TRUNCATION_LIMIT, - notes="Curated daily papers feed backed by HfApi.list_daily_papers. Useful join points: organization, submitted_by, author_usernames, discussion_id.", + notes="Returns daily paper summary rows. repo_id is omitted unless the upstream payload provides it.", ), pagination={"default_limit": 20, "max_limit": OUTPUT_ITEMS_TRUNCATION_LIMIT}, ), - "hf_papers_search": _config( - "hf_papers_search", - endpoint_patterns=(r"^/api/papers/search$",), - default_metadata=_metadata( - default_fields=PAPER_DEFAULT_FIELDS, - guaranteed_fields=["paper_id", "title", "published_at"], - optional_fields=PAPER_OPTIONAL_FIELDS, - default_limit=20, - max_limit=OUTPUT_ITEMS_TRUNCATION_LIMIT, - notes="Paper search helper backed by HfApi.list_papers. Use organization, submitted_by, and author_usernames as the main Hub-native join points.", - ), - pagination={"default_limit": 20, "max_limit": OUTPUT_ITEMS_TRUNCATION_LIMIT}, - ), - "hf_paper_info": _config( - "hf_paper_info", - endpoint_patterns=(r"^/api/papers/[^/]+$",), - default_metadata=_metadata( - default_fields=PAPER_DEFAULT_FIELDS, - guaranteed_fields=["paper_id", "title", "published_at"], - optional_fields=PAPER_OPTIONAL_FIELDS, - notes="Exact paper metadata helper backed by HfApi.paper_info.", - ), - ), - "hf_read_paper": _config( - "hf_read_paper", - endpoint_patterns=(r"^/papers/[^/]+\.md$",), - default_metadata=_metadata( - default_fields=PAPER_CONTENT_DEFAULT_FIELDS, - guaranteed_fields=["paper_id", "content"], - optional_fields=[], - notes="Returns paper markdown content backed by HfApi.read_paper.", - ), - ), "hf_collections_search": _config( "hf_collections_search", endpoint_patterns=(r"^/api/collections$",), @@ -664,9 +630,6 @@ ALLOWLIST_PATTERNS = [ r"^/api/whoami-v2$", r"^/api/trending$", r"^/api/daily_papers$", - r"^/api/papers/search$", - r"^/api/papers/[^/]+$", - r"^/papers/[^/]+\.md$", r"^/api/models$", r"^/api/datasets$", r"^/api/spaces$", @@ -697,9 +660,6 @@ STRICT_ALLOWLIST_PATTERNS = [ r"^/api/whoami-v2$", r"^/api/trending$", r"^/api/daily_papers$", - r"^/api/papers/search$", - r"^/api/papers/[^/]+$", - r"^/papers/[^/]+\.md$", r"^/api/(models|datasets|spaces)/(?:[^/]+|[^/]+/[^/]+)/likers$", r"^/api/collections$", r"^/api/collections/[^/]+$", diff --git a/monty_api/runtime_context.py b/monty_api/runtime_context.py index afaf0e6eb23f122596ce49baa7e83352337e5a76..49eb536ba281e24e0aa92cde316c693fd1dd45fc 100644 --- a/monty_api/runtime_context.py +++ b/monty_api/runtime_context.py @@ -12,7 +12,6 @@ from .constants import MAX_CALLS_LIMIT from .helpers.activity import register_activity_helpers from .helpers.collections import register_collection_helpers from .helpers.introspection import register_introspection_helpers -from .helpers.papers import register_paper_helpers from .helpers.profiles import register_profile_helpers from .helpers.repos import register_repo_helpers from .http_runtime import ( @@ -27,6 +26,7 @@ from .http_runtime import ( _extract_profile_name, _load_token, _normalize_collection_repo_item, + _normalize_daily_paper_row, _normalize_repo_detail_row, _normalize_repo_search_row, _normalize_repo_sort_key, @@ -64,6 +64,7 @@ from .runtime_filtering import ( _project_collection_items, _project_discussion_detail_items, _project_discussion_items, + _project_daily_paper_items, _project_items, _project_repo_items, _project_user_items, @@ -340,6 +341,7 @@ for name, value in { "_project_collection_items": _project_collection_items, "_project_discussion_items": _project_discussion_items, "_project_discussion_detail_items": _project_discussion_detail_items, + "_project_daily_paper_items": _project_daily_paper_items, "_project_user_items": _project_user_items, "_project_actor_items": _project_actor_items, "_project_user_like_items": _project_user_like_items, @@ -360,6 +362,7 @@ for name, value in { "_extract_profile_name": staticmethod(_extract_profile_name), "_load_token": staticmethod(_load_token), "_normalize_collection_repo_item": staticmethod(_normalize_collection_repo_item), + "_normalize_daily_paper_row": staticmethod(_normalize_daily_paper_row), "_normalize_repo_detail_row": staticmethod(_normalize_repo_detail_row), "_normalize_repo_search_row": staticmethod(_normalize_repo_search_row), "_normalize_repo_sort_key": staticmethod(_normalize_repo_sort_key), @@ -388,7 +391,6 @@ def build_runtime_helper_environment( for registration in ( register_profile_helpers, register_repo_helpers, - register_paper_helpers, register_activity_helpers, register_collection_helpers, register_introspection_helpers, diff --git a/monty_api/runtime_filtering.py b/monty_api/runtime_filtering.py index 665afbe1af3c0e783414ecd23ddfd2dcc478266d..68e6c3a5de06ff9aede310b4dcccae45ea800b3b 100644 --- a/monty_api/runtime_filtering.py +++ b/monty_api/runtime_filtering.py @@ -7,6 +7,7 @@ from .constants import ( ACTIVITY_CANONICAL_FIELDS, ACTOR_CANONICAL_FIELDS, COLLECTION_CANONICAL_FIELDS, + DAILY_PAPER_CANONICAL_FIELDS, DISCUSSION_CANONICAL_FIELDS, DISCUSSION_DETAIL_CANONICAL_FIELDS, REPO_CANONICAL_FIELDS, @@ -82,6 +83,14 @@ def _project_collection_items( ) +def _project_daily_paper_items( + self: Any, items: list[dict[str, Any]], fields: list[str] | None +) -> list[dict[str, Any]]: + return _project_items( + self, items, fields, allowed_fields=DAILY_PAPER_CANONICAL_FIELDS + ) + + def _project_user_items( self: Any, items: list[dict[str, Any]], fields: list[str] | None ) -> list[dict[str, Any]]: