From 8650aa7419b439b8d25074df347b19acc73597cc Mon Sep 17 00:00:00 2001 From: Musa Date: Tue, 13 Jan 2026 11:00:41 -0800 Subject: [PATCH] Revert "add init command" This reverts commit a181ef153d5ec2c2781573b35376c75f40789506. --- cli/planoai/consts.py | 3 - cli/planoai/init_cmd.py | 701 ----------------------- cli/planoai/main.py | 2 - cli/pyproject.toml | 1 - cli/test/test_init.py | 59 -- cli/uv.lock | 35 -- demos/use_cases/vercel-ai-sdk/.env.local | 5 - 7 files changed, 806 deletions(-) delete mode 100644 cli/planoai/init_cmd.py delete mode 100644 cli/test/test_init.py delete mode 100644 demos/use_cases/vercel-ai-sdk/.env.local diff --git a/cli/planoai/consts.py b/cli/planoai/consts.py index 1c0400fb..5b137fa6 100644 --- a/cli/planoai/consts.py +++ b/cli/planoai/consts.py @@ -1,8 +1,5 @@ import os -# Brand color - Plano purple -PLANO_COLOR = "#969FF4" - SERVICE_NAME_ARCHGW = "plano" PLANO_DOCKER_NAME = "plano" PLANO_DOCKER_IMAGE = os.getenv("PLANO_DOCKER_IMAGE", "katanemo/plano:0.4.2") diff --git a/cli/planoai/init_cmd.py b/cli/planoai/init_cmd.py deleted file mode 100644 index a4f5c6f8..00000000 --- a/cli/planoai/init_cmd.py +++ /dev/null @@ -1,701 +0,0 @@ -import re -import os -from dataclasses import dataclass -from pathlib import Path - -import rich_click as click -from rich.console import Console -from rich.panel import Panel - -from planoai.consts import PLANO_COLOR -from planoai.utils import get_llm_provider_access_keys, find_repo_root - - -@dataclass(frozen=True) -class Template: - """ - A Plano config template. - - - id: stable identifier used by --template - - title/description: UI strings - - yaml_text: embedded template contents (works in PyPI installs) - - repo_path: optional path to a real demos/.../config.yaml when running in-repo - """ - - id: str - title: str - description: str - yaml_text: str | None = None - repo_path: str | None = None - - -BUILTIN_TEMPLATES: list[Template] = [ - Template( - id="samples_python/weather_forecast", - title="samples_python/weather_forecast", - description="prompt targets + multiple LLMs (OpenAI/Groq/Anthropic)", - yaml_text="""version: v0.1.0 - -listeners: - ingress_traffic: - address: 0.0.0.0 - port: 10000 - message_format: openai - timeout: 30s - - egress_traffic: - address: 0.0.0.0 - port: 12000 - message_format: openai - timeout: 30s - -endpoints: - weather_forecast_service: - endpoint: host.docker.internal:18083 - connect_timeout: 0.005s - -overrides: - prompt_target_intent_matching_threshold: 0.6 - -llm_providers: - - access_key: $GROQ_API_KEY - model: groq/llama-3.2-3b-preview - - - access_key: $OPENAI_API_KEY - model: openai/gpt-4o - default: true - - - access_key: $OPENAI_API_KEY - model: openai/gpt-4o-mini - - - access_key: $ANTHROPIC_API_KEY - model: anthropic/claude-sonnet-4-20250514 - -system_prompt: | - You are a helpful assistant. - -prompt_targets: - - name: get_current_weather - description: Get current weather at a location. - parameters: - - name: location - description: The location to get the weather for - required: true - type: string - format: City, State - - name: days - description: the number of days for the request - required: true - type: int - endpoint: - name: weather_forecast_service - path: /weather - http_method: POST - - - name: default_target - default: true - description: This is the default target for all unmatched prompts. - endpoint: - name: weather_forecast_service - path: /default_target - http_method: POST - system_prompt: | - You are a helpful assistant! Summarize the user's request and provide a helpful response. - auto_llm_dispatch_on_response: false - -tracing: - random_sampling: 100 - trace_arch_internal: true -""", - ), - Template( - id="samples_python/stock_quote", - title="samples_python/stock_quote", - description="external API headers ($TWELVEDATA_API_KEY) + prompt targets", - yaml_text="""version: v0.1.0 - -listeners: - ingress_traffic: - address: 0.0.0.0 - port: 10000 - message_format: openai - timeout: 30s - -llm_providers: - - access_key: $OPENAI_API_KEY - model: openai/gpt-4o - -endpoints: - twelvedata_api: - endpoint: api.twelvedata.com - protocol: https - -system_prompt: | - You are a helpful assistant. - -prompt_targets: - - name: stock_quote - description: get current stock exchange rate for a given symbol - parameters: - - name: symbol - description: Stock symbol - required: true - type: str - endpoint: - name: twelvedata_api - path: /quote - http_headers: - Authorization: "apikey $TWELVEDATA_API_KEY" - system_prompt: | - You are a helpful stock exchange assistant. Parse the JSON and present it in a human-readable format. Be concise. - - - name: stock_quote_time_series - description: get historical stock exchange rate for a given symbol - parameters: - - name: symbol - description: Stock symbol - required: true - type: str - - name: interval - description: Time interval - default: 1day - enum: - - 1h - - 1day - type: str - endpoint: - name: twelvedata_api - path: /time_series - http_headers: - Authorization: "apikey $TWELVEDATA_API_KEY" - system_prompt: | - You are a helpful stock exchange assistant. Parse the JSON and present it in a human-readable format. Be concise. - -tracing: - random_sampling: 100 - trace_arch_internal: true -""", - ), - Template( - id="use_cases/claude_code_router", - title="use_cases/claude_code_router", - description="multi-model routing preferences + model_aliases (good for CLI agents)", - yaml_text="""version: v0.1 - -listeners: - egress_traffic: - address: 0.0.0.0 - port: 12000 - message_format: openai - timeout: 30s - -llm_providers: - - model: openai/gpt-5-2025-08-07 - access_key: $OPENAI_API_KEY - routing_preferences: - - name: code generation - description: generating new code snippets, functions, or boilerplate based on user prompts or requirements - - - model: openai/gpt-4.1-2025-04-14 - access_key: $OPENAI_API_KEY - routing_preferences: - - name: code understanding - description: understand and explain existing code snippets, functions, or libraries - - - model: anthropic/claude-sonnet-4-5 - default: true - access_key: $ANTHROPIC_API_KEY - - - model: anthropic/claude-haiku-4-5 - access_key: $ANTHROPIC_API_KEY - - - model: ollama/llama3.1 - base_url: http://host.docker.internal:11434 - -model_aliases: - arch.claude.code.small.fast: - target: claude-haiku-4-5 - -tracing: - random_sampling: 100 -""", - ), - Template( - id="use_cases/ollama", - title="use_cases/ollama", - description="local LLM via base_url (OpenAI-compatible provider_interface)", - yaml_text="""version: v0.1.0 - -listeners: - egress_traffic: - address: 0.0.0.0 - port: 12000 - message_format: openai - timeout: 30s - -llm_providers: - - model: my_llm_provider/llama3.2 - provider_interface: openai - base_url: http://host.docker.internal:11434 - default: true - -system_prompt: | - You are a helpful assistant. - -tracing: - random_sampling: 100 - trace_arch_internal: true -""", - ), -] - - -def _discover_repo_demo_templates(repo_root: str | None) -> dict[str, str]: - """ - Returns mapping from template id -> absolute config.yaml path for repo demos. - This is best-effort and should be fast; built-in templates remain the default. - """ - if not repo_root: - return {} - demos_dir = Path(repo_root) / "demos" - if not demos_dir.exists(): - return {} - - result: dict[str, str] = {} - # keep it bounded: just walk demos and match config.yaml (small tree) - for cfg in demos_dir.rglob("config.yaml"): - try: - rel = cfg.relative_to(demos_dir).as_posix() - except Exception: - continue - template_id = rel.removesuffix("/config.yaml") - result[template_id] = str(cfg) - return result - - -def _get_templates() -> list[Template]: - repo_root = find_repo_root() - repo_templates = _discover_repo_demo_templates(repo_root) - templates: list[Template] = [] - for t in BUILTIN_TEMPLATES: - repo_path = repo_templates.get(t.id) - templates.append( - Template( - id=t.id, - title=t.title, - description=t.description, - yaml_text=t.yaml_text, - repo_path=repo_path, - ) - ) - - # Add any extra demo configs not represented by built-ins (no embedded yaml). - builtin_ids = {t.id for t in templates} - for template_id, path in sorted(repo_templates.items()): - if template_id in builtin_ids: - continue - templates.append( - Template( - id=template_id, - title=template_id, - description="(repo demo)", - yaml_text=None, - repo_path=path, - ) - ) - return templates - - -def _resolve_template(template_id_or_path: str | None) -> Template | None: - if not template_id_or_path: - return None - - # 1) explicit path - p = Path(template_id_or_path) - if p.exists() and p.is_file(): - return Template( - id=str(p), - title=str(p), - description="(file)", - yaml_text=None, - repo_path=str(p.resolve()), - ) - - # 2) known id - templates = _get_templates() - for t in templates: - if t.id == template_id_or_path: - return t - - return None - - -def _ensure_parent_dir(path: Path) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - - -def _write_clean_config(path: Path, force: bool) -> None: - _ensure_parent_dir(path) - if path.exists() and not force: - raise FileExistsError(str(path)) - # user asked for NOTHING in it: empty file, with just a newline for POSIX friendliness - path.write_text("\n", encoding="utf-8") - - -def _write_template_config(path: Path, template: Template, force: bool) -> str: - _ensure_parent_dir(path) - if path.exists() and not force: - raise FileExistsError(str(path)) - - if template.repo_path: - src = Path(template.repo_path) - text = src.read_text(encoding="utf-8") - path.write_text(text, encoding="utf-8") - return f"repo:{template.repo_path}" - - if template.yaml_text is None: - raise ValueError(f"Template '{template.id}' is not available in this install.") - - path.write_text(template.yaml_text, encoding="utf-8") - return "builtin" - - -_ENV_VAR_PATTERN = re.compile(r"\$\{?([A-Z_][A-Z0-9_]*)\}?") - - -def _extract_env_vars(config_path: Path) -> list[str]: - """ - Extract env vars referenced by the config so we can offer .env placeholders. - Uses existing logic (headers/model providers/etc) plus a regex fallback. - """ - keys: set[str] = set() - try: - extracted = get_llm_provider_access_keys(str(config_path)) - for item in extracted: - if not item: - continue - if item.startswith("$"): - keys.add(item[1:]) - else: - # some cases may return raw vars - keys.add(item) - except Exception: - # best-effort; still run regex scan - pass - - try: - text = config_path.read_text(encoding="utf-8") - for m in _ENV_VAR_PATTERN.findall(text): - keys.add(m) - except Exception: - pass - - # Filter obvious false positives if any ever appear - keys.discard("HOST") - keys.discard("PORT") - return sorted(keys) - - -def _read_env_file_keys(env_path: Path) -> set[str]: - if not env_path.exists(): - return set() - keys: set[str] = set() - for line in env_path.read_text(encoding="utf-8").splitlines(): - s = line.strip() - if not s or s.startswith("#") or "=" not in s: - continue - k = s.split("=", 1)[0].strip() - if k: - keys.add(k) - return keys - - -def _upsert_env_placeholders(env_path: Path, keys: list[str]) -> list[str]: - """ - Create or append missing keys with blank values. Returns the keys actually added. - """ - _ensure_parent_dir(env_path) - existing = _read_env_file_keys(env_path) - missing = [k for k in keys if k not in existing] - if not missing: - return [] - - header = "" - if env_path.exists(): - header = "\n# Added by `planoai init`\n" - - addition = header + "\n".join([f"{k}=" for k in missing]) + "\n" - with env_path.open("a", encoding="utf-8") as f: - f.write(addition) - return missing - - -def _questionary_style(): - # prompt_toolkit style string format - from prompt_toolkit.styles import Style - - return Style.from_dict( - { - "qmark": f"fg:{PLANO_COLOR} bold", - "question": "bold", - "answer": f"fg:{PLANO_COLOR} bold", - "pointer": f"fg:{PLANO_COLOR} bold", - "highlighted": f"fg:{PLANO_COLOR} bold", - "selected": f"fg:{PLANO_COLOR}", - "instruction": "fg:#888888", - "text": "", - "disabled": "fg:#666666", - } - ) - - -def _force_truecolor_for_prompt_toolkit() -> None: - """ - Ensure prompt_toolkit uses truecolor so our brand hex (#969FF4) renders correctly. - Without this, some terminals or environments downgrade to 8-bit and the color - can look like a generic blue. - """ - # Only set if user hasn't explicitly chosen a depth. - os.environ.setdefault("PROMPT_TOOLKIT_COLOR_DEPTH", "DEPTH_24_BIT") - - -@click.command() -@click.option( - "--template", - "template_id_or_path", - default=None, - help="Create config.yaml from a template id (e.g. use_cases/claude_code_router) or a path to a YAML file.", -) -@click.option( - "--clean", - is_flag=True, - help="Create an empty config.yaml with no contents.", -) -@click.option( - "--output", - "-o", - "output_path", - default="config.yaml", - show_default=True, - help="Where to write the generated config.", -) -@click.option( - "--force", - is_flag=True, - help="Overwrite existing config file if it already exists.", -) -@click.option( - "--no-env", - is_flag=True, - help="Do not create/update a .env file.", -) -@click.option( - "--yes", - "-y", - is_flag=True, - help="Skip interactive prompts and accept defaults (will NOT overwrite without --force).", -) -@click.option( - "--list-templates", - is_flag=True, - help="List available template ids and exit.", -) -@click.pass_context -def init( - ctx, template_id_or_path, clean, output_path, force, no_env, yes, list_templates -): - """Initialize a Plano config quickly (arrow-key interactive wizard by default).""" - import sys - - console = Console() - - if clean and template_id_or_path: - raise click.UsageError("Use either --clean or --template, not both.") - - templates = _get_templates() - - if list_templates: - console.print(f"[bold {PLANO_COLOR}]Available templates[/bold {PLANO_COLOR}]\n") - for t in templates: - origin = ( - "repo" if t.repo_path else "builtin" if t.yaml_text else "repo-only" - ) - console.print( - f" [bold]{t.id}[/bold] [dim]({origin})[/dim] - {t.description}" - ) - return - - out_path = Path(output_path).expanduser() - - # Non-interactive fast paths - if yes or clean or template_id_or_path: - if clean: - try: - _write_clean_config(out_path, force=force) - except FileExistsError: - raise click.ClickException( - f"Refusing to overwrite existing file: {out_path} (use --force)" - ) - console.print(f"[green]✓[/green] Wrote [bold]{out_path}[/bold]") - return - - if template_id_or_path: - template = _resolve_template(template_id_or_path) - if not template: - raise click.ClickException( - f"Unknown template: {template_id_or_path}\n" - f"Run: planoai init --list-templates" - ) - try: - origin = _write_template_config(out_path, template, force=force) - except FileExistsError: - raise click.ClickException( - f"Refusing to overwrite existing file: {out_path} (use --force)" - ) - console.print( - f"[green]✓[/green] Wrote [bold]{out_path}[/bold] [dim]({template.id}, {origin})[/dim]" - ) - - if no_env: - return - - env_vars = _extract_env_vars(out_path) - if env_vars: - env_path = out_path.parent / ".env" - added = _upsert_env_placeholders(env_path, env_vars) - if added: - console.print( - f"[green]✓[/green] Updated [bold]{env_path}[/bold] [dim](added: {', '.join(added)})[/dim]" - ) - else: - console.print(f"[dim]✓ .env already contains required keys[/dim]") - return - - # yes without clean/template means: do nothing useful - raise click.UsageError( - "Non-interactive mode requires --template or --clean (or omit --yes for the interactive wizard)." - ) - - # Interactive wizard - if not (sys.stdin.isatty() and sys.stdout.isatty()): - raise click.ClickException( - "Interactive mode requires a TTY.\n" - "Use one of:\n" - " planoai init --template \n" - " planoai init --clean\n" - " planoai init --list-templates" - ) - - _force_truecolor_for_prompt_toolkit() - - # Lazy import so non-interactive users don't pay the import/compat cost - import questionary - from questionary import Choice - - # Step 1: mode - mode = questionary.select( - "Welcome to Plano! Pick a starting point:", - choices=[ - Choice("Start from a demo template (recommended)", value="template"), - Choice("Create a clean config.yaml (empty)", value="clean"), - Choice("Cancel", value="cancel"), - ], - style=_questionary_style(), - pointer="❯", - ).ask() - - if mode in (None, "cancel"): - console.print("[dim]Cancelled.[/dim]") - return - - # Step 2: output path (default: config.yaml) - out_answer = questionary.text( - "Where should I write the config?", - default=str(out_path), - style=_questionary_style(), - ).ask() - if not out_answer: - console.print("[dim]Cancelled.[/dim]") - return - out_path = Path(out_answer).expanduser() - - if out_path.exists() and not force: - overwrite = questionary.confirm( - f"{out_path} already exists. Overwrite?", - default=False, - style=_questionary_style(), - ).ask() - if not overwrite: - console.print("[dim]Cancelled.[/dim]") - return - force = True - - if mode == "clean": - _write_clean_config(out_path, force=True) - console.print(f"[green]✓[/green] Wrote [bold]{out_path}[/bold]") - return - - # Step 3: choose template (curated at top, plus any repo-only demos) - # Keep the list compact and readable. - template_choices: list[Choice] = [] - for t in templates: - label = f"{t.title} — {t.description}" - template_choices.append(Choice(label, value=t)) - - template = questionary.select( - "Choose a template", - choices=template_choices, - style=_questionary_style(), - pointer="❯", - use_indicator=True, - ).ask() - if not template: - console.print("[dim]Cancelled.[/dim]") - return - - origin = _write_template_config(out_path, template, force=True) - console.print( - f"[green]✓[/green] Wrote [bold]{out_path}[/bold] [dim]({template.id}, {origin})[/dim]" - ) - - # Step 4: .env placeholders (recommended, fast) - if not no_env: - env_vars = _extract_env_vars(out_path) - if env_vars: - env_path = out_path.parent / ".env" - do_env = questionary.confirm( - "Create/update a .env file with placeholders for required keys?", - default=True, - style=_questionary_style(), - ).ask() - if do_env: - added = _upsert_env_placeholders(env_path, env_vars) - if added: - console.print( - f"[green]✓[/green] Updated [bold]{env_path}[/bold] [dim](added: {', '.join(added)})[/dim]" - ) - else: - console.print(f"[dim]✓ .env already contains required keys[/dim]") - - # Step 5: next step shortcuts (validate/up/done) - next_step = questionary.select( - "Next step", - choices=[ - Choice(f"Run: planoai validate {out_path}", value="validate"), - Choice(f"Run: planoai up {out_path}", value="up"), - Choice("Done", value="done"), - ], - default="validate", - style=_questionary_style(), - pointer="❯", - ).ask() - - if next_step == "validate": - # Reuse existing click command implementation - from planoai.main import validate as validate_cmd - - ctx.invoke(validate_cmd, config_file=str(out_path), path=".", quiet=False) - elif next_step == "up": - from planoai.main import up as up_cmd - - ctx.invoke(up_cmd, file=str(out_path), path=".", foreground=False) diff --git a/cli/planoai/main.py b/cli/planoai/main.py index b18258c6..151da306 100644 --- a/cli/planoai/main.py +++ b/cli/planoai/main.py @@ -93,7 +93,6 @@ from planoai.core import ( stop_docker_container, start_cli_agent, ) -from planoai.init_cmd import init as init_cmd from planoai.consts import ( PLANO_DOCKER_IMAGE, PLANO_DOCKER_NAME, @@ -880,7 +879,6 @@ main.add_command(logs) main.add_command(cli_agent) main.add_command(generate_prompt_targets) main.add_command(validate) -main.add_command(init_cmd, name="init") if __name__ == "__main__": main() diff --git a/cli/pyproject.toml b/cli/pyproject.toml index b901d4c2..be5ba0ca 100644 --- a/cli/pyproject.toml +++ b/cli/pyproject.toml @@ -9,7 +9,6 @@ dependencies = [ "click>=8.1.7,<9.0.0", "jinja2>=3.1.4,<4.0.0", "jsonschema>=4.23.0,<5.0.0", - "questionary>=2.1.1,<3.0.0", "pyyaml>=6.0.2,<7.0.0", "requests>=2.31.0,<3.0.0", "rich>=14.2.0", diff --git a/cli/test/test_init.py b/cli/test/test_init.py deleted file mode 100644 index ccbae873..00000000 --- a/cli/test/test_init.py +++ /dev/null @@ -1,59 +0,0 @@ -from click.testing import CliRunner - -from planoai.init_cmd import init - - -def test_init_clean_writes_empty_config(tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - - runner = CliRunner() - result = runner.invoke(init, ["--clean"]) - - assert result.exit_code == 0, result.output - config_path = tmp_path / "config.yaml" - assert config_path.exists() - assert config_path.read_text(encoding="utf-8") == "\n" - - -def test_init_template_builtin_writes_config_and_env(tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - - runner = CliRunner() - result = runner.invoke( - init, ["--template", "use_cases/claude_code_router", "--yes"] - ) - - assert result.exit_code == 0, result.output - - config_path = tmp_path / "config.yaml" - assert config_path.exists() - config_text = config_path.read_text(encoding="utf-8") - assert "llm_providers:" in config_text - - env_path = tmp_path / ".env" - assert env_path.exists() - env_text = env_path.read_text(encoding="utf-8") - assert "OPENAI_API_KEY=" in env_text - assert "ANTHROPIC_API_KEY=" in env_text - - -def test_init_refuses_overwrite_without_force(tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - (tmp_path / "config.yaml").write_text("hello", encoding="utf-8") - - runner = CliRunner() - result = runner.invoke(init, ["--clean"]) - - assert result.exit_code != 0 - assert "Refusing to overwrite" in result.output - - -def test_init_force_overwrites(tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - (tmp_path / "config.yaml").write_text("hello", encoding="utf-8") - - runner = CliRunner() - result = runner.invoke(init, ["--clean", "--force"]) - - assert result.exit_code == 0, result.output - assert (tmp_path / "config.yaml").read_text(encoding="utf-8") == "\n" diff --git a/cli/uv.lock b/cli/uv.lock index 2a3b1edc..764badcc 100644 --- a/cli/uv.lock +++ b/cli/uv.lock @@ -271,7 +271,6 @@ dependencies = [ { name = "jinja2" }, { name = "jsonschema" }, { name = "pyyaml" }, - { name = "questionary" }, { name = "requests" }, { name = "rich" }, { name = "rich-click" }, @@ -294,7 +293,6 @@ requires-dist = [ { name = "jsonschema", specifier = ">=4.23.0,<5.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.4.1,<9.0.0" }, { name = "pyyaml", specifier = ">=6.0.2,<7.0.0" }, - { name = "questionary", specifier = ">=2.1.1,<3.0.0" }, { name = "requests", specifier = ">=2.31.0,<3.0.0" }, { name = "rich", specifier = ">=14.2.0" }, { name = "rich-click", specifier = ">=1.9.5" }, @@ -313,18 +311,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] -[[package]] -name = "prompt-toolkit" -version = "3.0.52" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, -] - [[package]] name = "pygments" version = "2.19.2" @@ -396,18 +382,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, ] -[[package]] -name = "questionary" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "prompt-toolkit" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f6/45/eafb0bba0f9988f6a2520f9ca2df2c82ddfa8d67c95d6625452e97b204a5/questionary-2.1.1.tar.gz", hash = "sha256:3d7e980292bb0107abaa79c68dd3eee3c561b83a0f89ae482860b181c8bd412d", size = 25845, upload-time = "2025-08-28T19:00:20.851Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl", hash = "sha256:a51af13f345f1cdea62347589fbb6df3b290306ab8930713bfae4d475a7d4a59", size = 36753, upload-time = "2025-08-28T19:00:19.56Z" }, -] - [[package]] name = "referencing" version = "0.36.2" @@ -656,12 +630,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599 wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] - -[[package]] -name = "wcwidth" -version = "0.2.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, -] diff --git a/demos/use_cases/vercel-ai-sdk/.env.local b/demos/use_cases/vercel-ai-sdk/.env.local deleted file mode 100644 index 63f81dd7..00000000 --- a/demos/use_cases/vercel-ai-sdk/.env.local +++ /dev/null @@ -1,5 +0,0 @@ -AUTH_SECRET=R/dTqODnkO4dHsra7q9J78GkBTHG2YKWVnRZdTIYxmw= -AI_GATEWAY_API_KEY=vck_8OmwGvVjwIZvNnOUtXQe7QrwbJY9iqT1VkVmM1JtstIbJsazj71lCMGf -BLOB_READ_WRITE_TOKEN=vercel_blob_rw_m2VnAfbbbo7gcEMm_o6M0Zj7v7OLcz8W4fuJXTzjK6dcTSV -POSTGRES_URL=postgresql://neondb_owner:npg_bkr8fYJiw7HA@ep-wandering-surf-ahvhyf3o-pooler.c-3.us-east-1.aws.neon.tech/neondb?sslmode=require -REDIS_URL="rediss://default:ATU7AAIncDJkMmFlOTMxNjA2ZTI0ZTJmOGU0YWFhNTYxYjhmZmU1OXAyMTM2Mjc@ethical-monster-13627.upstash.io:6379"