omnilane 0.8.3 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # omnilane runner: any OpenAI-compatible /chat/completions endpoint.
5
+ #
6
+ # Usage: run-openai-compat.sh MODE WORKDIR MODEL EFFORT PROMPT_FILE OUTPUT_FILE
7
+ # Driven by run-<vendor>.sh wrappers that export OMNILANE_OAI_VENDOR. Like the
8
+ # openrouter runner this is pure inference over HTTPS — no agentic loop, so
9
+ # work mode is a hard error, not a silent read-only downgrade.
10
+ #
11
+ # Base URL, API-key env var, and a model hint come from vendor_api_spec. The
12
+ # base URL is overridable per vendor via <VENDOR>_BASE_URL. EFFORT is accepted
13
+ # for interface parity only. Needs curl and the vendor's API key; python3
14
+ # builds/parses the JSON so prompt content never needs shell escaping.
15
+
16
+ source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
17
+
18
+ MODE="$1"; WORKDIR="$2"; MODEL="$3"; EFFORT="$4"; PROMPT_FILE="$5"; OUTPUT_FILE="$6"
19
+ : "$WORKDIR" "$EFFORT" # parity with the uniform runner interface
20
+
21
+ fail() { echo "omnilane: $1" > "${OUTPUT_FILE}.stderr.log"; exit 2; }
22
+
23
+ VENDOR="${OMNILANE_OAI_VENDOR:?run-openai-compat.sh must be invoked via a run-<vendor>.sh wrapper}"
24
+ SPEC="$(vendor_api_spec "$VENDOR")"
25
+ [[ -n "$SPEC" ]] || fail "unknown OpenAI-compatible vendor '$VENDOR'"
26
+ BASE_DEFAULT="${SPEC%%|*}"
27
+ MODEL_HINT="${SPEC##*|}"
28
+ KEY_ENV="${SPEC#*|}"; KEY_ENV="${KEY_ENV%%|*}"
29
+
30
+ VENDOR_UPPER="$(printf '%s' "$VENDOR" | tr '[:lower:]' '[:upper:]')"
31
+ BASE_OVERRIDE_VAR="${VENDOR_UPPER}_BASE_URL"
32
+ BASE_URL="${!BASE_OVERRIDE_VAR:-$BASE_DEFAULT}"
33
+ API_KEY="${!KEY_ENV:-}"
34
+ RUN_TIMEOUT="${OMNILANE_TIMEOUT:-600}"
35
+
36
+ [[ "$MODE" == "advise" ]] || fail "$VENDOR is inference-only: use --mode advise (work mode needs an agentic CLI vendor like opencode)"
37
+ [[ -n "$API_KEY" ]] || fail "$KEY_ENV is not set"
38
+ [[ -n "$MODEL" && "$MODEL" != "-" ]] || fail "$VENDOR needs an explicit model slug (e.g. $MODEL_HINT)"
39
+ command -v curl >/dev/null 2>&1 || fail "curl not found"
40
+ command -v python3 >/dev/null 2>&1 || fail "python3 not found"
41
+
42
+ truncate_payload "$PROMPT_FILE" 140000
43
+
44
+ REQUEST_FILE="${OUTPUT_FILE}.request.json"
45
+ RESPONSE_FILE="${OUTPUT_FILE}.response.json"
46
+ # Keep the API key out of the process argument list (ps-visible): curl reads the
47
+ # Authorization header from a 0600 file, not a -H command-line flag.
48
+ HEADER_FILE="${OUTPUT_FILE}.headers"
49
+ cleanup() { rm "$REQUEST_FILE" "$RESPONSE_FILE" "$HEADER_FILE" 2>/dev/null || true; }
50
+ trap cleanup EXIT
51
+ ( umask 077; printf 'Authorization: Bearer %s\n' "$API_KEY" > "$HEADER_FILE" )
52
+
53
+ python3 - "$MODEL" "$PROMPT_FILE" > "$REQUEST_FILE" <<'PY'
54
+ import json, sys
55
+ model, prompt_file = sys.argv[1], sys.argv[2]
56
+ with open(prompt_file, encoding="utf-8", errors="replace") as f:
57
+ prompt = f.read()
58
+ json.dump({"model": model, "messages": [{"role": "user", "content": prompt}]},
59
+ sys.stdout)
60
+ PY
61
+
62
+ set +e
63
+ run_with_timeout "$RUN_TIMEOUT" curl -sS --fail-with-body \
64
+ --max-time "$RUN_TIMEOUT" \
65
+ -H "@$HEADER_FILE" \
66
+ -H "Content-Type: application/json" \
67
+ -X POST "$BASE_URL/chat/completions" \
68
+ --data-binary "@$REQUEST_FILE" \
69
+ > "$RESPONSE_FILE" 2> "${OUTPUT_FILE}.stderr.log"
70
+ RC=$?
71
+ set -e
72
+
73
+ if [[ "$RC" -ne 0 ]]; then
74
+ # Surface the API error body (never the key) alongside curl's own stderr.
75
+ [[ -s "$RESPONSE_FILE" ]] && cat "$RESPONSE_FILE" >> "${OUTPUT_FILE}.stderr.log"
76
+ exit "$RC"
77
+ fi
78
+
79
+ set +e
80
+ python3 - "$VENDOR" "$RESPONSE_FILE" > "${OUTPUT_FILE}.tmp" 2>> "${OUTPUT_FILE}.stderr.log" <<'PY'
81
+ import json, sys
82
+ vendor = sys.argv[1]
83
+ with open(sys.argv[2], encoding="utf-8", errors="replace") as f:
84
+ data = json.load(f)
85
+ if "error" in data:
86
+ print(f"omnilane: {vendor} API error: {data['error']}", file=sys.stderr)
87
+ sys.exit(1)
88
+ content = data["choices"][0]["message"]["content"]
89
+ sys.stdout.write(content if isinstance(content, str) else json.dumps(content))
90
+ PY
91
+ RC=$?
92
+ set -e
93
+
94
+ # Empty output is a failure, not a silent rc=0 success.
95
+ if ! grep -q '[^[:space:]]' "${OUTPUT_FILE}.tmp" 2>/dev/null; then
96
+ echo "omnilane: $VENDOR produced no output" >> "${OUTPUT_FILE}.stderr.log"
97
+ if [[ "$RC" -eq 0 ]]; then RC=1; fi
98
+ fi
99
+
100
+ [[ -f "${OUTPUT_FILE}.tmp" ]] && mv "${OUTPUT_FILE}.tmp" "$OUTPUT_FILE"
101
+ [[ -s "${OUTPUT_FILE}.stderr.log" ]] || rm "${OUTPUT_FILE}.stderr.log" 2>/dev/null || true
102
+ exit "$RC"
@@ -1,86 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
-
4
- # omnilane runner: OpenRouter direct API (no CLI dependency)
5
- #
6
- # Usage: run-openrouter.sh MODE WORKDIR MODEL EFFORT PROMPT_FILE OUTPUT_FILE
7
- # MODE = advise only. This vendor is pure inference over HTTPS — it has no
8
- # agentic loop and cannot edit files, so work mode is a hard error rather
9
- # than a silent read-only downgrade.
10
- #
11
- # MODEL is an OpenRouter model slug (e.g. anthropic/claude-sonnet-4). EFFORT
12
- # is accepted for interface parity only. Needs OPENROUTER_API_KEY and curl;
13
- # python3 builds/parses the JSON so prompt content never needs shell escaping.
14
-
15
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
16
-
17
- MODE="$1"; WORKDIR="$2"; MODEL="$3"; EFFORT="$4"; PROMPT_FILE="$5"; OUTPUT_FILE="$6"
18
- : "$WORKDIR" "$EFFORT" # parity with the uniform runner interface
19
-
20
- OPENROUTER_BASE_URL="${OPENROUTER_BASE_URL:-https://openrouter.ai/api/v1}"
21
- RUN_TIMEOUT="${OMNILANE_TIMEOUT:-600}"
22
-
23
- fail() { echo "omnilane: $1" > "${OUTPUT_FILE}.stderr.log"; exit 2; }
24
-
25
- [[ "$MODE" == "advise" ]] || fail "openrouter is inference-only: use --mode advise (work mode needs an agentic CLI vendor like opencode)"
26
- [[ -n "${OPENROUTER_API_KEY:-}" ]] || fail "OPENROUTER_API_KEY is not set"
27
- [[ -n "$MODEL" && "$MODEL" != "-" ]] || fail "openrouter needs an explicit model slug (e.g. anthropic/claude-sonnet-4)"
28
- command -v curl >/dev/null 2>&1 || fail "curl not found"
29
- command -v python3 >/dev/null 2>&1 || fail "python3 not found"
30
-
31
- truncate_payload "$PROMPT_FILE" 140000
32
-
33
- REQUEST_FILE="${OUTPUT_FILE}.request.json"
34
- RESPONSE_FILE="${OUTPUT_FILE}.response.json"
35
- cleanup() { rm "$REQUEST_FILE" "$RESPONSE_FILE" 2>/dev/null || true; }
36
- trap cleanup EXIT
37
-
38
- python3 - "$MODEL" "$PROMPT_FILE" > "$REQUEST_FILE" <<'PY'
39
- import json, sys
40
- model, prompt_file = sys.argv[1], sys.argv[2]
41
- with open(prompt_file, encoding="utf-8", errors="replace") as f:
42
- prompt = f.read()
43
- json.dump({"model": model, "messages": [{"role": "user", "content": prompt}]},
44
- sys.stdout)
45
- PY
46
-
47
- set +e
48
- run_with_timeout "$RUN_TIMEOUT" curl -sS --fail-with-body \
49
- --max-time "$RUN_TIMEOUT" \
50
- -H "Authorization: Bearer $OPENROUTER_API_KEY" \
51
- -H "Content-Type: application/json" \
52
- -X POST "$OPENROUTER_BASE_URL/chat/completions" \
53
- --data-binary "@$REQUEST_FILE" \
54
- > "$RESPONSE_FILE" 2> "${OUTPUT_FILE}.stderr.log"
55
- RC=$?
56
- set -e
57
-
58
- if [[ "$RC" -ne 0 ]]; then
59
- # Surface the API error body (never the key) alongside curl's own stderr.
60
- [[ -s "$RESPONSE_FILE" ]] && cat "$RESPONSE_FILE" >> "${OUTPUT_FILE}.stderr.log"
61
- exit "$RC"
62
- fi
63
-
64
- set +e
65
- python3 - "$RESPONSE_FILE" > "${OUTPUT_FILE}.tmp" 2>> "${OUTPUT_FILE}.stderr.log" <<'PY'
66
- import json, sys
67
- with open(sys.argv[1], encoding="utf-8", errors="replace") as f:
68
- data = json.load(f)
69
- if "error" in data:
70
- print(f"omnilane: openrouter API error: {data['error']}", file=sys.stderr)
71
- sys.exit(1)
72
- content = data["choices"][0]["message"]["content"]
73
- sys.stdout.write(content if isinstance(content, str) else json.dumps(content))
74
- PY
75
- RC=$?
76
- set -e
77
-
78
- # Empty output is a failure, not a silent rc=0 success.
79
- if ! grep -q '[^[:space:]]' "${OUTPUT_FILE}.tmp" 2>/dev/null; then
80
- echo "omnilane: openrouter produced no output" >> "${OUTPUT_FILE}.stderr.log"
81
- [[ "$RC" -eq 0 ]] && RC=1
82
- fi
83
-
84
- [[ -f "${OUTPUT_FILE}.tmp" ]] && mv "${OUTPUT_FILE}.tmp" "$OUTPUT_FILE"
85
- [[ -s "${OUTPUT_FILE}.stderr.log" ]] || rm "${OUTPUT_FILE}.stderr.log" 2>/dev/null || true
86
- exit "$RC"
3
+ # omnilane runner: OpenRouter (OpenAI-compatible direct API). Thin wrapper over
4
+ # run-openai-compat.sh; endpoint and default model live in vendor_api_spec.
5
+ # Override the endpoint with OPENROUTER_BASE_URL; needs OPENROUTER_API_KEY.
6
+ export OMNILANE_OAI_VENDOR=openrouter
7
+ exec "$(dirname "${BASH_SOURCE[0]}")/run-openai-compat.sh" "$@"
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ # omnilane runner: Z.ai GLM (OpenAI-compatible direct API). Thin wrapper over
4
+ # run-openai-compat.sh; endpoint and default model live in vendor_api_spec.
5
+ # Override the endpoint with ZAI_BASE_URL; needs ZAI_API_KEY.
6
+ export OMNILANE_OAI_VENDOR=zai
7
+ exec "$(dirname "${BASH_SOURCE[0]}")/run-openai-compat.sh" "$@"