1 Commits

Author SHA1 Message Date
HRiggs 58a57ddc6a fix: config saving and config loading
Build Release EXE / build-windows-exe (release) Successful in 50s
2026-05-06 15:18:51 -04:00
9 changed files with 38 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
OLLAMA_BASE_URL=http://localhost:11434 OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen3.5:9b OLLAMA_MODEL=qwen3.5:9b
OLLAMA_NUM_CTX=64000 OLLAMA_NUM_CTX=64512
UEX_BASE_URL=https://api.uexcorp.space/2.0 UEX_BASE_URL=https://api.uexcorp.space/2.0
UEX_SECRET_KEY= UEX_SECRET_KEY=
UEX_BEARER_TOKEN= UEX_BEARER_TOKEN=
+1 -1
View File
@@ -34,7 +34,7 @@ Local Ollama-powered chat for UEX marketplace workflows.
## Notes ## Notes
Ollama runs locally at `http://localhost:11434` by default. This app talks to Ollama's native chat API with tool schemas, then executes approved UEX calls in the FastAPI backend. `OLLAMA_NUM_CTX` controls the per-request Ollama context window; `64000` is the default because Ollama recommends at least 64k tokens for agent-style workflows when hardware allows it. Ollama runs locally at `http://localhost:11434` by default. This app talks to Ollama's native chat API with tool schemas, then executes approved UEX calls in the FastAPI backend. `OLLAMA_NUM_CTX` controls the per-request Ollama context window; `64512` is the default because Ollama recommends at least 64k tokens for agent-style workflows when hardware allows it.
## Releases And Updates ## Releases And Updates
+2 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "traderai" name = "traderai"
version = "0.0.1" version = "0.0.2"
description = "Local Ollama-powered assistant for UEX marketplace workflows." description = "Local Ollama-powered assistant for UEX marketplace workflows."
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [
@@ -35,3 +35,4 @@ include = ["traderai*"]
+16
View File
@@ -13,6 +13,7 @@ from traderai.tools import ToolRegistry
SYSTEM_PROMPT = """You are TraderAI, a local assistant for UEX marketplace work. SYSTEM_PROMPT = """You are TraderAI, a local assistant for UEX marketplace work.
Use tools when the user asks about UEX data, open/current listings, active negotiations, unread notifications, messages, offers, or posting ads. Use tools when the user asks about UEX data, open/current listings, active negotiations, unread notifications, messages, offers, or posting ads.
UEX credentials are configured server-side when available. Never ask the user to provide UEX_SECRET_KEY or UEX_BEARER_TOKEN in chat; call the authenticated UEX tool and only mention credential configuration if the tool returns an authentication error.
Use the specific UEX tool for the needed endpoint, such as get_uex_commodities_prices or get_uex_vehicles. Use fields, limit, and summary mode so tool results stay compact. Use the specific UEX tool for the needed endpoint, such as get_uex_commodities_prices or get_uex_vehicles. Use fields, limit, and summary mode so tool results stay compact.
When the user asks for history, trends, changes over time, or past prices, prefer the summarize_uex_*_history tools when available; use search_uex_api_index(history_only=true) if you need to discover history endpoints. When the user asks for history, trends, changes over time, or past prices, prefer the summarize_uex_*_history tools when available; use search_uex_api_index(history_only=true) if you need to discover history endpoints.
Prefer open and current UEX marketplace information. Do not use historical sale data, completed sale records, or sale/average-history information unless the user explicitly asks for historical sales. Prefer open and current UEX marketplace information. Do not use historical sale data, completed sale records, or sale/average-history information unless the user explicitly asks for historical sales.
@@ -215,6 +216,21 @@ class OllamaAgent:
parts = [ parts = [
f"Current local date/time: {iso_now()} UTC; {iso_now_in_zone(local_zone)} {local_zone}.", f"Current local date/time: {iso_now()} UTC; {iso_now_in_zone(local_zone)} {local_zone}.",
] ]
uex = getattr(self.tools, "uex", None)
if uex:
auth_methods = []
if uex.secret_key:
auth_methods.append("secret key")
if uex.bearer_token:
auth_methods.append("bearer token")
if auth_methods:
parts.append(
"UEX API authentication is configured server-side with "
+ " and ".join(auth_methods)
+ "; use authenticated UEX tools directly and do not ask for tokens."
)
else:
parts.append("UEX API authentication is not configured server-side.")
if self.user_name: if self.user_name:
parts.append(f"Known user name/handle: {self.user_name}.") parts.append(f"Known user name/handle: {self.user_name}.")
+9 -1
View File
@@ -62,7 +62,7 @@ class Settings(BaseSettings):
ollama_base_url: str = "http://localhost:11434" ollama_base_url: str = "http://localhost:11434"
ollama_model: str = "qwen3.5:9b" ollama_model: str = "qwen3.5:9b"
ollama_num_ctx: int = 64000 ollama_num_ctx: int = 64512
uex_base_url: str = "https://api.uexcorp.space/2.0" uex_base_url: str = "https://api.uexcorp.space/2.0"
uex_secret_key: str | None = Field(default=None) uex_secret_key: str | None = Field(default=None)
uex_bearer_token: str | None = Field(default=None) uex_bearer_token: str | None = Field(default=None)
@@ -90,6 +90,11 @@ def get_settings() -> Settings:
def settings_payload(settings: Settings | None = None) -> dict[str, Any]: def settings_payload(settings: Settings | None = None) -> dict[str, Any]:
current = settings or get_settings() current = settings or get_settings()
values = current.model_dump() values = current.model_dump()
secrets_configured = {}
for key, meta in CONFIG_FIELDS.items():
if meta.get("secret"):
secrets_configured[key] = bool(values.get(key))
values[key] = ""
return { return {
"app_data_dir": str(ensure_app_data_dir()), "app_data_dir": str(ensure_app_data_dir()),
"config_path": str(user_config_path()), "config_path": str(user_config_path()),
@@ -97,6 +102,7 @@ def settings_payload(settings: Settings | None = None) -> dict[str, Any]:
"edge_profile_dir": str(edge_profile_dir()), "edge_profile_dir": str(edge_profile_dir()),
"values": values, "values": values,
"fields": CONFIG_FIELDS, "fields": CONFIG_FIELDS,
"secrets_configured": secrets_configured,
} }
@@ -106,6 +112,8 @@ def save_settings(values: dict[str, Any]) -> dict[str, Any]:
for key, value in values.items(): for key, value in values.items():
if key not in CONFIG_FIELDS: if key not in CONFIG_FIELDS:
continue continue
if CONFIG_FIELDS[key].get("secret") and value == "":
continue
next_values[key] = _coerce_value(key, value) next_values[key] = _coerce_value(key, value)
path = user_config_path() path = user_config_path()
+2 -1
View File
@@ -1,9 +1,10 @@
from __future__ import annotations from __future__ import annotations
__version__ = "0.0.1" __version__ = "0.0.2"
RELEASES_URL = "https://git.hudsonriggs.systems/LambdaBankingConglomerate/TraderAI/releases" RELEASES_URL = "https://git.hudsonriggs.systems/LambdaBankingConglomerate/TraderAI/releases"
RELEASES_API_URL = "https://git.hudsonriggs.systems/api/v1/repos/LambdaBankingConglomerate/TraderAI/releases" RELEASES_API_URL = "https://git.hudsonriggs.systems/api/v1/repos/LambdaBankingConglomerate/TraderAI/releases"
Generated
+2 -1
View File
@@ -755,7 +755,7 @@ wheels = [
[[package]] [[package]]
name = "traderai" name = "traderai"
version = "0.0.1" version = "0.0.2"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "apscheduler" }, { name = "apscheduler" },
@@ -1047,3 +1047,4 @@ wheels = [
+5 -4
View File
@@ -416,9 +416,6 @@ function fetchErrorMessage(error) {
} }
const configFieldIds = { const configFieldIds = {
ollama_base_url: "config-ollama-base-url",
ollama_model: "config-ollama-model",
ollama_num_ctx: "config-ollama-num-ctx",
uex_base_url: "config-uex-base-url", uex_base_url: "config-uex-base-url",
uex_secret_key: "config-uex-secret-key", uex_secret_key: "config-uex-secret-key",
uex_bearer_token: "config-uex-bearer-token", uex_bearer_token: "config-uex-bearer-token",
@@ -446,11 +443,15 @@ async function refreshConfig() {
function renderConfig(config) { function renderConfig(config) {
const values = config.values || {}; const values = config.values || {};
const secretsConfigured = config.secrets_configured || {};
for (const [key, id] of Object.entries(configFieldIds)) { for (const [key, id] of Object.entries(configFieldIds)) {
const field = document.getElementById(id); const field = document.getElementById(id);
if (!field) continue; if (!field) continue;
if (field.type === "checkbox") { if (field.type === "checkbox") {
field.checked = Boolean(values[key]); field.checked = Boolean(values[key]);
} else if (field.type === "password") {
field.value = "";
field.placeholder = secretsConfigured[key] ? "Configured" : "";
} else { } else {
field.value = values[key] ?? ""; field.value = values[key] ?? "";
} }
@@ -572,7 +573,7 @@ async function postOllamaAction(endpoint, options = {}) {
} }
function configuredOllamaModel() { function configuredOllamaModel() {
return document.getElementById("ollama-model")?.value || document.getElementById("config-ollama-model")?.value || ""; return document.getElementById("ollama-model")?.value || "";
} }
async function checkForUpdate() { async function checkForUpdate() {
-3
View File
@@ -59,9 +59,6 @@
<button class="secondary small-button" id="config-refresh" type="button">Refresh</button> <button class="secondary small-button" id="config-refresh" type="button">Refresh</button>
</div> </div>
<form class="config-form" id="config-form"> <form class="config-form" id="config-form">
<label>Ollama URL<input id="config-ollama-base-url" name="ollama_base_url" type="text"></label>
<label>Ollama Model<input id="config-ollama-model" name="ollama_model" type="text"></label>
<label>Context Tokens<input id="config-ollama-num-ctx" name="ollama_num_ctx" type="number" min="1024" step="1024"></label>
<label>UEX API URL<input id="config-uex-base-url" name="uex_base_url" type="text"></label> <label>UEX API URL<input id="config-uex-base-url" name="uex_base_url" type="text"></label>
<label>UEX Secret Key<input id="config-uex-secret-key" name="uex_secret_key" type="password" autocomplete="off"></label> <label>UEX Secret Key<input id="config-uex-secret-key" name="uex_secret_key" type="password" autocomplete="off"></label>
<label>UEX Bearer Token<input id="config-uex-bearer-token" name="uex_bearer_token" type="password" autocomplete="off"></label> <label>UEX Bearer Token<input id="config-uex-bearer-token" name="uex_bearer_token" type="password" autocomplete="off"></label>