Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/cloud-staging-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ jobs:
- name: Setup extension
run: |
cd tmp_extension
npm install
npm run compile:ts
npm install -g @vscode/vsce@3.3.2
npm run build
vsce package
Expand Down Expand Up @@ -182,4 +180,4 @@ jobs:
git commit -m "version $VERSION"
git push origin staging
fi
cd ..
cd ..
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# (2025-08-18)
# (2025-08-25)


### Reverts

* Revert "Implemented weekend discount" ([734e0c7](https://github.com/Pythagora-io/pythagora-v1/commit/734e0c726b179a45f235a0fd230a6310c77ae740))



24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

<div align="center">

[![Discord Follow](https://dcbadge.vercel.app/api/server/HaqXugmxr9?style=flat)](https://discord.gg/HaqXugmxr9)
[![Discord](https://img.shields.io/badge/Discord-Join%20Us-5865F2?style=social&logo=discord)](https://discord.gg/HaqXugmxr9)
[![GitHub Repo stars](https://img.shields.io/github/stars/Pythagora-io/gpt-pilot?style=social)](https://github.com/Pythagora-io/gpt-pilot)
[![Twitter Follow](https://img.shields.io/twitter/follow/HiPythagora?style=social)](https://twitter.com/HiPythagora)
[![Twitter Follow](https://img.shields.io/twitter/follow/PythagoraAI?style=social)](https://x.com/PythagoraAI)

</div>

Expand All @@ -28,29 +28,37 @@
<br>

<div align="center">

### GPT Pilot doesn't just generate code, it builds apps!

</div>

<div align="center">

This repo is not being maintained anymore.

# Visit [Pythagora.ai](https://www.pythagora.ai/) for more info

</div>

---
<div align="center">

[![See it in action](https://i3.ytimg.com/vi/4g-1cPGK0GA/maxresdefault.jpg)](https://youtu.be/4g-1cPGK0GA)
[![See it in action](https://img.youtube.com/vi/o1nEvwjKziw/0.jpg)]([https://youtu.be/4g-1cPGK0GA](https://www.youtube.com/watch?v=o1nEvwjKziw))

(click to open the video in YouTube) (1:40min)
(click to open the video in YouTube) (1:04min)

</div>

---

<div align="center">

<a href="vscode:extension/PythagoraTechnologies.gpt-pilot-vs-code" target="_blank"><img src="https://github.com/Pythagora-io/gpt-pilot/assets/10895136/5792143e-77c7-47dd-ad96-6902be1501cd" alt="Pythagora-io%2Fgpt-pilot | Trendshift" style="width: 185px; height: 55px;" width="185" height="55"/></a>
<a href="https://marketplace.visualstudio.com/items?itemName=PythagoraTechnologies.pythagora-vs-code" target="_blank"><img src="https://github.com/Pythagora-io/gpt-pilot/assets/10895136/5792143e-77c7-47dd-ad96-6902be1501cd" alt="Pythagora-io%2Fgpt-pilot | Trendshift" style="width: 185px; height: 55px;" width="185" height="55"/></a>

</div>

GPT Pilot is the core technology for the [Pythagora VS Code extension](https://bit.ly/3IeZxp6) that aims to provide **the first real AI developer companion**. Not just an autocomplete or a helper for PR messages but rather a real AI developer that can write full features, debug them, talk to you about issues, ask for review, etc.
GPT Pilot is the core technology for the [Pythagora VS Code extension](https://marketplace.visualstudio.com/items?itemName=PythagoraTechnologies.pythagora-vs-code) that aims to provide **the first real AI developer companion**. Not just an autocomplete or a helper for PR messages but rather a real AI developer that can write full features, debug them, talk to you about issues, ask for review, etc.

---

Expand Down Expand Up @@ -112,7 +120,7 @@ After you have Python and (optionally) PostgreSQL installed, follow these steps:
5. `pip install -r requirements.txt` (install the dependencies)
6. `cp example-config.json config.json` (create `config.json` file)
7. Set your key and other settings in `config.json` file:
- LLM Provider (`openai`, `anthropic` or `groq`) key and endpoints (leave `null` for default) (note that Azure and OpenRouter are suppored via the `openai` setting)
- LLM Provider (`openai`, `anthropic`, `groq` or `minimax`) key and endpoints (leave `null` for default) (note that Azure and OpenRouter are suppored via the `openai` setting)
- Your API key (if `null`, will be read from the environment variables)
- database settings: sqlite is used by default, PostgreSQL should also work
- optionally update `fs.ignore_paths` and add files or folders which shouldn't be tracked by GPT Pilot in workspace, useful to ignore folders created by compilers
Expand Down
6 changes: 1 addition & 5 deletions core/agents/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from core.llm.parser import DescriptiveCodeBlockParser, OptionalCodeBlockParser
from core.log import get_logger
from core.telemetry import telemetry
from core.ui.base import ProjectStage, UISource
from core.ui.base import ProjectStage

log = get_logger(__name__)

Expand Down Expand Up @@ -168,10 +168,6 @@ async def iterate_frontend(self):
if user_input:
await self.send_message("Errors detected, fixing...")
else:
await self.ui.send_message(
"Use code CODE20 and subscribe https://pythagora.ai/pricing",
source=UISource("Congratulations", "success"),
)
answer = await self.ask_question(
"Do you want to change anything or report a bug?" if frontend_only else FE_CHANGE_REQ,
buttons={"yes": "I'm done building the UI"} if not frontend_only else None,
Expand Down
5 changes: 1 addition & 4 deletions core/agents/spec_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from core.log import get_logger
from core.telemetry import telemetry
from core.templates.registry import PROJECT_TEMPLATES
from core.ui.base import ProjectStage, UISource
from core.ui.base import ProjectStage

log = get_logger(__name__)

Expand Down Expand Up @@ -122,9 +122,6 @@ async def initialize_spec_and_project(self) -> AgentResponse:

await self.ui.send_front_logs_headers("specs_0", ["E1 / T1", "Writing Specification", "working"], "")

await self.ui.send_message(
"Use code CODE20 and subscribe https://pythagora.ai/pricing", source=UISource("Congratulations", "success")
)
await self.send_message(
"## Write specification\n\nPythagora is generating a detailed specification for app based on your input.",
# project_state_id="setup",
Expand Down
1 change: 1 addition & 0 deletions core/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class LLMProvider(str, Enum):
GROQ = "groq"
LM_STUDIO = "lm-studio"
AZURE = "azure"
MINIMAX = "minimax"


class UIAdapter(str, Enum):
Expand Down
3 changes: 3 additions & 0 deletions core/llm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ def for_provider(provider: LLMProvider) -> type["BaseLLMClient"]:
from .anthropic_client import AnthropicClient
from .azure_client import AzureClient
from .groq_client import GroqClient
from .minimax_client import MiniMaxClient
from .openai_client import OpenAIClient
from .relace_client import RelaceClient

Expand All @@ -436,6 +437,8 @@ def for_provider(provider: LLMProvider) -> type["BaseLLMClient"]:
return GroqClient
elif provider == LLMProvider.AZURE:
return AzureClient
elif provider == LLMProvider.MINIMAX:
return MiniMaxClient
else:
raise ValueError(f"Unsupported LLM provider: {provider.value}")

Expand Down
126 changes: 126 additions & 0 deletions core/llm/minimax_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import datetime
import os
import re
from typing import Optional

import tiktoken
from httpx import Timeout
from openai import AsyncOpenAI, RateLimitError

from core.config import LLMProvider
from core.llm.base import BaseLLMClient
from core.llm.convo import Convo
from core.log import get_logger

log = get_logger(__name__)
tokenizer = tiktoken.get_encoding("cl100k_base")

# MiniMax API base URL (international)
MINIMAX_BASE_URL = "https://api.minimax.io/v1"

# MiniMax temperature must be in (0.0, 1.0], cannot be 0
MINIMAX_MIN_TEMPERATURE = 0.01


class MiniMaxClient(BaseLLMClient):
provider = LLMProvider.MINIMAX

def _init_client(self):
api_key = self.config.api_key or os.environ.get("MINIMAX_API_KEY")
self.client = AsyncOpenAI(
api_key=api_key,
base_url=self.config.base_url or MINIMAX_BASE_URL,
timeout=Timeout(
max(self.config.connect_timeout, self.config.read_timeout),
connect=self.config.connect_timeout,
read=self.config.read_timeout,
),
)

async def _make_request(
self,
convo: Convo,
temperature: Optional[float] = None,
json_mode: bool = False,
) -> tuple[str, int, int]:
temp = self.config.temperature if temperature is None else temperature
# MiniMax requires temperature > 0
if temp <= 0:
temp = MINIMAX_MIN_TEMPERATURE

completion_kwargs = {
"model": self.config.model,
"messages": convo.messages,
"temperature": temp,
"stream": True,
}

# MiniMax does not support response_format; skip json_mode

stream = await self.client.chat.completions.create(**completion_kwargs)
response = []
prompt_tokens = 0
completion_tokens = 0

async for chunk in stream:
if chunk.usage:
prompt_tokens += chunk.usage.prompt_tokens
completion_tokens += chunk.usage.completion_tokens

if not chunk.choices:
continue

content = chunk.choices[0].delta.content
if not content:
continue

response.append(content)
if self.stream_handler:
await self.stream_handler(content)

response_str = "".join(response)

# Tell the stream handler we're done
if self.stream_handler:
await self.stream_handler(None)

if prompt_tokens == 0 and completion_tokens == 0:
prompt_tokens = sum(3 + len(tokenizer.encode(msg["content"])) for msg in convo.messages)
completion_tokens = len(tokenizer.encode(response_str))
log.warning(
"MiniMax response did not include token counts, estimating with tiktoken: "
f"{prompt_tokens} input tokens, {completion_tokens} output tokens"
)

return response_str, prompt_tokens, completion_tokens

def rate_limit_sleep(self, err: RateLimitError) -> Optional[datetime.timedelta]:
"""
Handle MiniMax rate limiting using OpenAI-compatible headers.
"""
headers = err.response.headers
if "x-ratelimit-remaining-tokens" not in headers:
# Check for retry-after header as fallback
if "retry-after" in headers:
return datetime.timedelta(seconds=int(headers["retry-after"]))
return None

remaining_tokens = headers["x-ratelimit-remaining-tokens"]
time_regex = r"(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?"
if remaining_tokens == 0:
match = re.search(time_regex, headers.get("x-ratelimit-reset-tokens", ""))
else:
match = re.search(time_regex, headers.get("x-ratelimit-reset-requests", ""))

if match:
hours = int(match.group(1)) if match.group(1) else 0
minutes = int(match.group(2)) if match.group(2) else 0
seconds = int(match.group(3)) if match.group(3) else 0
total_seconds = hours * 3600 + minutes * 60 + seconds
else:
total_seconds = 5

return datetime.timedelta(seconds=total_seconds)


__all__ = ["MiniMaxClient"]
8 changes: 8 additions & 0 deletions example-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
"azure_deployment": "your-azure-deployment-id",
"api_version": "2024-02-01"
}
},
// Example config for MiniMax (see https://platform.minimax.io/docs/api-reference/text-openai-api)
// Available models: MiniMax-M3 (default), MiniMax-M2.7, MiniMax-M2.7-highspeed
"minimax": {
"base_url": "https://api.minimax.io/v1",
"api_key": "your-minimax-api-key",
"connect_timeout": 60.0,
"read_timeout": 20.0
}
},
// Each agent can use a different model or configuration. The default, as before, is GPT4 Turbo
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pythagora-core"
version = "2.0.9"
version = "2.0.10"
description = "Build complete apps using AI agents"
authors = ["Leon Ostrez <leon@pythagora.ai>"]
license = "FSL-1.1-MIT"
Expand Down
Loading