inter-hub-haskell/scripts/llm_bridge.py

68 lines
2.1 KiB
Python
Raw Normal View History

feat(WP-0012): IHF Phase 11 — Advanced AI Federation - Schema: AgentRegistration, ModelRoutingPolicy, AgentDelegation, CollectiveProposal, CollectiveProposalContribution, AiGovernancePolicy, AgentPerformanceRecord + ALTER TABLE agent_proposals (migration 1744156800; CHECK constraints on trust_level, status, consensus_status — GAAF compliant) - Bridge: scripts/llm_bridge.py (llm-connect subprocess seam) + Application/Helper/AgentBridge.hs (callBridge, callAgent, checkGovernancePolicy, jsonArrayTexts) - Routing: Application/Helper/ModelRouter.hs (resolveAgent, resolveAllAgents) + ModelRoutingPolicies CRUD - Registry: AgentRegistrations CRUD (Index/Show/New/Edit/Performance), DeactivateAgentAction, ComputeAgentPerformanceAction - Delegation: AgentDelegations controller + views, DelegateSubtaskAction with token budget enforcement at bridge call time - Collective: CollectiveProposals controller + views, CreateCollectiveProposalAction (fan-out → synthesis → consensus detection) - Governance: AiGovernancePolicies CRUD + ToggleAiGovernancePolicyAction; checkGovernancePolicy enforced at all 4 Phase 5 invocation points - Phase 5 wiring: replaced callClaudeApi in Widgets, DecisionRecords, RequirementCandidates with resolveAgent + callAgent + token tracking - llm-connect feature requests: ~/llm-connect/FEATURE_REQUESTS.md (FR-1 HTTP serve, FR-2 RoutingPolicy, FR-3 async, FR-4 BudgetTracker) - GAAF scorecard: 3.61 (up from 3.56); Functional 3.4→3.6, Extensions 3.8→3.9 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 20:57:17 +00:00
#!/usr/bin/env python3
"""
IHF llm-connect bridge Phase 11 AI Federation (IHUB-WP-0012)
Usage:
echo '{"provider":"openrouter","model":"...","prompt":"..."}' | python3 scripts/llm_bridge.py
Input JSON fields:
provider openrouter | gemini | openai | claude-code (default: openrouter)
model model name string (provider-specific)
prompt the user prompt
systemPrompt optional system prompt
api_key optional; falls back to llm-connect env-var resolution
maxTokens max completion tokens (default: 2000)
temperature sampling temperature (default: 0.7)
Output JSON (stdout, exit 0 on success):
content generated text
model model name actually used
tokensIn prompt token count
tokensOut completion token count
finishReason stop reason string
Error JSON (stdout, exit 1 on LLMError):
error error message
errorType exception class name
"""
import sys
import json
import os
sys.path.insert(0, os.path.expanduser("~/llm-connect"))
from llm_connect import create_adapter, RunConfig
from llm_connect.exceptions import LLMError
def main() -> None:
req = json.load(sys.stdin)
try:
adapter = create_adapter(
provider=req.get("provider", "openrouter"),
model=req.get("model"),
api_key=req.get("api_key"),
system_prompt=req.get("systemPrompt"),
)
config = RunConfig(
model_name=req.get("model", ""),
temperature=req.get("temperature", 0.7),
max_tokens=req.get("maxTokens", 2000),
)
resp = adapter.execute_prompt(req["prompt"], config)
print(json.dumps({
"content": resp.content,
"model": resp.model,
"tokensIn": resp.usage.get("prompt_tokens", 0),
"tokensOut": resp.usage.get("completion_tokens", 0),
"finishReason": resp.finish_reason,
}))
except LLMError as e:
json.dump({"error": str(e), "errorType": type(e).__name__}, sys.stdout)
sys.exit(1)
if __name__ == "__main__":
main()