Skip to content

Instantly share code, notes, and snippets.

@m13253
Last active October 11, 2026 03:16
Show Gist options
  • Select an option

  • Save m13253/40a8f5255c1994ce813317767c61420d to your computer and use it in GitHub Desktop.

Select an option

Save m13253/40a8f5255c1994ce813317767c61420d to your computer and use it in GitHub Desktop.
Convert Floway model list to oh-my-pi, Pi, VSCode, and Zed settings files
#!/usr/bin/env python3
# Usage:
# curl --oauth2-bearer '<API_KEY>' http://localhost:18088/v1/models | ./floway-to-omp.py [NAME] [API_URL]
# defaults: NAME=Floway, API_URL=http://localhost:18088/v1
#
# Installation:
# Pi: Install to ~/.pi/agent/models.json
# Oh-my-pi: Install to ~/.omp/agent/models.json and will be automatically converted to models.yml
# Then, inside Pi or oh-my-pi, type /login to configure your API key.
#
# Reference:
# https://pi.dev/docs/latest/models
# https://github.com/can1357/oh-my-pi/blob/main/docs/models.md
import decimal
import json
import sys
DEFAULT_UPSTREAM_NAME = "Floway"
DEFAULT_API_URL = "http://localhost:18088/v1"
def model_config(model):
chat = model.get("chat", {})
limits = model.get("limits", {})
rates = {}
for entry in model.get("pricing", {}).get("entries", []):
if not entry.get("selector"):
rates = entry.get("rates", {})
break
config = {
"id": model["id"],
"name": model.get("display_name", model["id"]),
"reasoning": True, # Force True until we fix Floway's metadata discovery
"thinkingLevelMap": {
"xhigh": "xhigh",
"max": "max",
}, # Force all possible reasoning efforts
}
if "input" in (modalities := chat.get("modalities", {})):
config["input"] = modalities["input"]
if "max_context_window_tokens" in limits:
config["contextWindow"] = limits["max_context_window_tokens"]
if "max_output_tokens" in limits:
config["maxTokens"] = limits["max_output_tokens"]
if (
"input_tokens" in rates
or "output_tokens" in rates
or "input_cache_read_tokens" in rates
or "input_cache_write_tokens" in rates
):
config["cost"] = {
"input": float(decimal.Decimal(rates.get("input_tokens", 0)).scaleb(6)),
"output": float(decimal.Decimal(rates.get("output_tokens", 0)).scaleb(6)),
"cacheRead": float(
decimal.Decimal(rates.get("input_cache_read_tokens", 0)).scaleb(6)
),
"cacheWrite": float(
decimal.Decimal(rates.get("input_cache_write_tokens", 0)).scaleb(6)
),
}
config["compat"] = {
"supportsStore": True,
}
return config
def main():
upstream = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_UPSTREAM_NAME
api_url = sys.argv[2] if len(sys.argv) > 2 else DEFAULT_API_URL
models = (
m
for m in json.load(sys.stdin.buffer)["data"]
if m.get("type") == "model" and m.get("kind") == "chat"
)
settings = {
"providers": {
upstream: {
"baseUrl": api_url,
"api": "openai-responses",
"authHeader": True,
"models": [model_config(m) for m in models],
}
}
}
print(json.dumps(settings, ensure_ascii=False, indent=4))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# Usage:
# curl --oauth2-bearer '<API_KEY>' http://localhost:18088/v1/models | ./floway-to-vscode.py [NAME] [API_URL]
# defaults: NAME=Floway, API_URL=http://localhost:18088/v1
#
# Installation:
# 1. Ctrl-Shift-P (Cmd-Shift-P): “Chat: Open Language Models (JSON)”, paste in the generated JSON
# 2. Ctrl-Shift-P (Cmd-Shift-P): “Developer: Reload Window”
# 3. Ctrl-Shift-P (Cmd-Shift-P): “Chat: Manage Language Models”
# 4. Right click a model, and choose “Update API Key”
#
# Reference:
# https://code.visualstudio.com/docs/agent-customization/language-models#_model-configuration-reference
import json
import sys
DEFAULT_UPSTREAM_NAME = "Floway"
DEFAULT_API_URL = "http://localhost:18088/v1"
DEFAULT_CONTEXT_WINDOW = 262144
DEFAULT_MAX_OUTPUT = 65536
SECRET_ID_PLACEHOLDER = "${input:chat.lm.secret.REPLACE_WITH_YOUR_SECRET_ID}"
def model_config(model, api_url):
chat = model.get("chat", {})
limits = model.get("limits", {})
max_context_window_tokens = limits.get("max_context_window_tokens")
max_input_tokens = limits.get("max_prompt_tokens")
max_output_tokens = limits.get("max_output_tokens")
match (
max_context_window_tokens is not None,
max_input_tokens is not None,
max_output_tokens is not None,
):
case False, False, False:
max_input_tokens = DEFAULT_CONTEXT_WINDOW - DEFAULT_MAX_OUTPUT
max_output_tokens = DEFAULT_MAX_OUTPUT
case False, False, True:
max_input_tokens = max(
DEFAULT_CONTEXT_WINDOW - max_output_tokens, max_output_tokens
)
case False, True, False:
max_output_tokens = max(max_input_tokens, DEFAULT_MAX_OUTPUT)
case _, True, True:
pass
case True, False, False:
max_output_tokens = min(max_context_window_tokens // 2, DEFAULT_MAX_OUTPUT)
max_input_tokens = max_context_window_tokens - max_output_tokens
case True, False, True:
max_input_tokens = max_context_window_tokens - max_output_tokens
case True, True, False:
max_output_tokens = max_context_window_tokens - max_input_tokens
config = {
"id": model["id"],
"name": model.get("display_name", model["id"]),
"url": api_url.rstrip("/") + "/responses",
"toolCalling": True,
"vision": "image" in chat.get("modalities", {}).get("input", []),
"thinking": True, # Force True until we fix Floway's metadata discovery
"maxInputTokens": max_input_tokens,
"maxOutputTokens": max_output_tokens,
}
if "reasoning" in chat:
config["reasoningEffortFormat"] = "responses"
if (effort := chat["reasoning"].get("effort")).get("supported"):
config["supportsReasoningEffort"] = list(effort["supported"])
return config
def main():
upstream = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_UPSTREAM_NAME
api_url = sys.argv[2] if len(sys.argv) > 2 else DEFAULT_API_URL
models = (
m
for m in json.load(sys.stdin.buffer)["data"]
if m.get("type") == "model" and m.get("kind") == "chat"
)
settings = [
{
"name": upstream,
"vendor": "customendpoint",
"apiKey": SECRET_ID_PLACEHOLDER,
"apiType": "responses",
"models": [model_config(m, api_url) for m in models],
}
]
print(json.dumps(settings, ensure_ascii=False, indent=4))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# Usage:
# curl --oauth2-bearer '<API_KEY>' http://localhost:18088/v1/models | ./floway-to-zed.py [NAME] [API_URL]
# defaults: NAME=Floway, API_URL=http://localhost:18088/v1
#
# Install to ~/.config/zed/global_settings.json
# Then, go to Zed Settings → User → AI → General → LLM Providers to configure your API key.
#
# Reference:
# https://zed.dev/docs/ai/use-api-access#openai-compatible
# zed://schemas/settings
import json
import sys
DEFAULT_UPSTREAM_NAME = "Floway"
DEFAULT_API_URL = "http://localhost:18088/v1"
DEFAULT_CONTEXT_WINDOW = 262144
def model_config(model):
chat = model.get("chat", {})
limits = model.get("limits", {})
config = {
"name": model["id"],
"display_name": model.get("display_name", model["id"]),
"max_tokens": limits.get("max_context_window_tokens", DEFAULT_CONTEXT_WINDOW),
"capabilities": {
"tools": True,
"images": "image" in chat.get("modalities", {}).get("input", []),
"parallel_tool_calls": True,
"prompt_cache_key": True,
"chat_completions": False,
"interleaved_reasoning": True,
},
}
return config
def main():
upstream = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_UPSTREAM_NAME
api_url = sys.argv[2] if len(sys.argv) > 2 else DEFAULT_API_URL
models = (
m
for m in json.load(sys.stdin.buffer)["data"]
if m.get("type") == "model" and m.get("kind") == "chat"
)
settings = {
"language_models": {
"openai_compatible": {
upstream: {
"api_url": api_url,
"available_models": [model_config(m) for m in models],
}
}
}
}
print(json.dumps(settings, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment