Adds a first-party Data Designer seed reader that scrapes GitHub issues, pull requests, and commits from one or more repositories via the GraphQL API, and a learning recipe (GitHub Support Bot) that turns those rows into synthetic support Q&A pairs for fine-tuning. Backend (new plugin studio/backend/plugins/data-designer-github-repo-seed): * GitHubRepoSeedSource config: repos, token (falls back to GH_TOKEN / GITHUB_TOKEN env var), item_types (issues / pulls / commits), per-resource limit (0 means all), max_comments_per_item. * Rate-limit-aware GraphQL client (GitHubClient + RepoScraper) shared across repos; flattens each item into a uniform row with columns item_type, repo, number, title, body, state, author, created_at, closed_at, url, labels, comments. * Registered via the data_designer.plugins entry point. Frontend: * New seed_github block variant so the seed node card shows "GitHub repositories" instead of the generic "Document file" placeholder, with its own icon and inline summary (repo count + item-type list). * Rewritten seed dialog github_repo form: repos textarea pre-filled with unslothai/unsloth + unslothai/unsloth-zoo, password input for the GH token, items-per-repo number with an "All" toggle, and the noisier options (item types, max comments, include comments) tucked under an Advanced collapsible. * Local model auto-load on Run: if a recipe uses an is_local provider and the inference server is not already serving that model, the executions hook calls /api/inference/load first. Removes the "open /chat to load a model" prerequisite that users kept tripping on. * Honor the recipe's run.rows value in the Run dialog (previously the store reset to 5 regardless of what the template shipped). Recipe (studio/frontend/src/features/data-recipes/learning-recipes/ github-support-bot.json): * Defaults to the Local Model provider + unsloth/gemma-4-E2B-it-GGUF. * Scrapes unslothai/unsloth and unslothai/unsloth-zoo, issues and pulls, up to 100 items per resource. * Two LLM blocks: normalized_question (llm-text) rewrites each thread into a clean support question, support_answer (llm-structured) produces JSON with answer / diagnosis_questions / cites / confidence. * Run defaults to 10 rows for a quick smoke test. Verified end-to-end on a running Studio: card renders, source-data dialog is pre-populated, All toggle disables the limit input, the recipe executes and produces rows against a loaded local GGUF.
124 lines
3.2 KiB
TypeScript
124 lines
3.2 KiB
TypeScript
// SPDX-License-Identifier: AGPL-3.0-only
|
|
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
|
|
|
import type { RecipeNodeData, LayoutDirection, NodeConfig } from "../types";
|
|
import {
|
|
labelForExpression,
|
|
labelForLlm,
|
|
labelForSampler,
|
|
} from "./config-labels";
|
|
|
|
export function nodeDataFromConfig(
|
|
config: NodeConfig,
|
|
layoutDirection: LayoutDirection = "LR",
|
|
): RecipeNodeData {
|
|
if (config.kind === "sampler") {
|
|
return {
|
|
title: "Generated field",
|
|
kind: "sampler",
|
|
subtype: labelForSampler(config.sampler_type),
|
|
blockType: config.sampler_type,
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "expression") {
|
|
return {
|
|
title: "Formula",
|
|
kind: "expression",
|
|
subtype: labelForExpression(config.dtype),
|
|
blockType: "expression",
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "validator") {
|
|
const isOxc = config.validator_type === "oxc";
|
|
const isSql = config.code_lang.startsWith("sql:");
|
|
let subtype = "Python";
|
|
let blockType: RecipeNodeData["blockType"] = "validator_python";
|
|
if (isOxc) {
|
|
subtype = "OXC";
|
|
blockType = "validator_oxc";
|
|
} else if (isSql) {
|
|
subtype = "SQL";
|
|
blockType = "validator_sql";
|
|
}
|
|
return {
|
|
title: "Check",
|
|
kind: "validator",
|
|
subtype,
|
|
blockType,
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "markdown_note") {
|
|
return {
|
|
title: "Note",
|
|
kind: "note",
|
|
subtype: "Markdown",
|
|
blockType: "markdown_note",
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "seed") {
|
|
const seedSourceType = config.seed_source_type ?? "hf";
|
|
const sourceLabel =
|
|
seedSourceType === "hf"
|
|
? "Hugging Face dataset"
|
|
: seedSourceType === "local"
|
|
? "CSV or JSON file"
|
|
: seedSourceType === "github_repo"
|
|
? "GitHub repositories"
|
|
: "Document file";
|
|
return {
|
|
title: "Source data",
|
|
kind: "seed",
|
|
subtype: sourceLabel,
|
|
blockType: "seed",
|
|
name: sourceLabel,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "model_provider") {
|
|
return {
|
|
title: "Provider connection",
|
|
kind: "model_provider",
|
|
subtype: config.provider_type || "Connection",
|
|
blockType: "model_provider",
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "model_config") {
|
|
return {
|
|
title: "Model preset",
|
|
kind: "model_config",
|
|
subtype: config.model || "Model",
|
|
blockType: "model_config",
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
if (config.kind === "tool_config") {
|
|
const providerCount = config.mcp_providers.length;
|
|
return {
|
|
title: "Tool access",
|
|
kind: "tool_config",
|
|
subtype: providerCount === 1 ? "1 server" : `${providerCount} servers`,
|
|
blockType: "tool_config",
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|
|
return {
|
|
title: "AI step",
|
|
kind: "llm",
|
|
subtype: labelForLlm(config.llm_type),
|
|
blockType: config.llm_type,
|
|
name: config.name,
|
|
layoutDirection,
|
|
};
|
|
}
|