Add project tools and strict provider execution

This commit is contained in:
rob
2026-07-20 22:27:36 -03:00
parent c289e812fb
commit 6a88fe2e0f
19 changed files with 1504 additions and 84 deletions
+81 -1
View File
@@ -44,6 +44,44 @@ class ProviderDialog(QDialog):
self.desc_input.setPlaceholderText("Claude AI via claude-cli")
form.addRow("Description:", self.desc_input)
self.locality_combo = QComboBox()
for value in ("unknown", "local", "remote"):
self.locality_combo.addItem(value.title(), value)
form.addRow("Locality:", self.locality_combo)
self.data_policy_combo = QComboBox()
for value in ("unspecified", "public", "internal", "private"):
self.data_policy_combo.addItem(value.title(), value)
form.addRow("Data policy:", self.data_policy_combo)
self.capabilities_input = QLineEdit()
self.capabilities_input.setPlaceholderText("text, structured-json, reasoning")
form.addRow("Capabilities:", self.capabilities_input)
self.model_input = QLineEdit()
self.model_input.setPlaceholderText("Model ID, if known")
form.addRow("Model:", self.model_input)
self.model_digest_input = QLineEdit()
self.model_digest_input.setPlaceholderText("sha256:... (verified local models)")
form.addRow("Model digest:", self.model_digest_input)
self.max_context_input = QLineEdit()
self.max_context_input.setPlaceholderText("Maximum context tokens")
form.addRow("Context tokens:", self.max_context_input)
self.cost_class_combo = QComboBox()
self.cost_class_combo.addItem("Unspecified", None)
for value in ("free", "low", "medium", "high"):
self.cost_class_combo.addItem(value.title(), value)
form.addRow("Cost class:", self.cost_class_combo)
self.latency_class_combo = QComboBox()
self.latency_class_combo.addItem("Unspecified", None)
for value in ("fast", "standard", "slow"):
self.latency_class_combo.addItem(value.title(), value)
form.addRow("Latency class:", self.latency_class_combo)
self.fallback_combo = QComboBox()
self.fallback_combo.addItem("(none)", None)
# Populate with available providers
@@ -86,6 +124,24 @@ class ProviderDialog(QDialog):
self.name_input.setEnabled(False) # Can't rename
self.cmd_input.setText(provider.command)
self.desc_input.setText(provider.description or "")
self.locality_combo.setCurrentIndex(
max(self.locality_combo.findData(provider.locality), 0)
)
self.data_policy_combo.setCurrentIndex(
max(self.data_policy_combo.findData(provider.data_policy), 0)
)
self.capabilities_input.setText(", ".join(provider.capabilities))
self.model_input.setText(provider.model or "")
self.model_digest_input.setText(provider.model_digest or "")
self.max_context_input.setText(
str(provider.max_context_tokens) if provider.max_context_tokens else ""
)
self.cost_class_combo.setCurrentIndex(
max(self.cost_class_combo.findData(provider.cost_class), 0)
)
self.latency_class_combo.setCurrentIndex(
max(self.latency_class_combo.findData(provider.latency_class), 0)
)
# Set fallback selection
if provider.fallback:
idx = self.fallback_combo.findData(provider.fallback)
@@ -107,6 +163,21 @@ class ProviderDialog(QDialog):
description = self.desc_input.text().strip()
fallback = self.fallback_combo.currentData()
capabilities = [
value.strip() for value in self.capabilities_input.text().split(",")
if value.strip()
]
try:
max_context_tokens = (
int(self.max_context_input.text().strip())
if self.max_context_input.text().strip() else None
)
except ValueError:
from PySide6.QtWidgets import QMessageBox
QMessageBox.warning(
self, "Invalid", "Context tokens must be a positive integer."
)
return
# Prevent self-referential fallback
if fallback == name:
@@ -122,12 +193,21 @@ class ProviderDialog(QDialog):
description=description,
fallback=fallback,
type=existing.type if existing else "subprocess",
model=existing.model if existing else None,
model=self.model_input.text().strip() or None,
tags=existing.tags if existing else [],
install=existing.install if existing else None,
fallback_chain=existing.fallback_chain if existing else None,
api_key_env=existing.api_key_env if existing else None,
pty_config=existing.pty_config if existing else None,
tools=existing.tools if existing else None,
mcp_servers=existing.mcp_servers if existing else None,
locality=self.locality_combo.currentData(),
capabilities=capabilities,
model_digest=self.model_digest_input.text().strip() or None,
cost_class=self.cost_class_combo.currentData(),
latency_class=self.latency_class_combo.currentData(),
max_context_tokens=max_context_tokens,
data_policy=self.data_policy_combo.currentData(),
))
self.accept()
except Exception as e:
+14 -1
View File
@@ -321,6 +321,15 @@ class PromptStepDialog(QDialog):
self.strip_fences_check = QCheckBox("Strip markdown code fences from output")
form.addRow("", self.strip_fences_check)
self.allow_fallback_check = QCheckBox(
"Allow configured fallback providers if this provider fails"
)
self.allow_fallback_check.setChecked(True)
self.allow_fallback_check.setToolTip(
"Disable for privacy-sensitive or reproducible steps that must fail closed."
)
form.addRow("", self.allow_fallback_check)
# Structured output options
form.addRow(QLabel("")) # Spacer
structured_label = QLabel("<b>Structured Output</b>")
@@ -455,6 +464,7 @@ class PromptStepDialog(QDialog):
self.output_input.setText(step.output_var)
self.prompt_input.setPlainText(step.prompt)
self.strip_fences_check.setChecked(step.strip_fences)
self.allow_fallback_check.setChecked(step.fallback_policy != "deny")
# Structured output fields
self.plain_text_check.setChecked(step.plain_text)
@@ -497,7 +507,10 @@ class PromptStepDialog(QDialog):
strip_fences=self.strip_fences_check.isChecked(),
output_schema=self._output_schema,
plain_text=self.plain_text_check.isChecked(),
max_retries=self.retries_spin.value()
max_retries=self.retries_spin.value(),
fallback_policy=(
"allow" if self.allow_fallback_check.isChecked() else "deny"
),
)