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.
- package/CHANGELOG.md +65 -1
- package/README.ja.md +147 -87
- package/README.ko.md +145 -86
- package/README.md +163 -90
- package/README.zh-CN.md +126 -78
- package/README.zh-TW.md +136 -74
- package/VERSION +1 -1
- package/bin/omnilane +4 -3
- package/bin/omnilane-mcp +291 -0
- package/completions/omnilane.fish +50 -0
- package/package.json +1 -1
- package/scripts/check.sh +125 -0
- package/scripts/configure.sh +151 -1
- package/scripts/dispatch.sh +4 -4
- package/scripts/doctor.sh +38 -0
- package/scripts/jobs.sh +132 -10
- package/scripts/lib/common.sh +57 -3
- package/scripts/runners/run-cerebras.sh +7 -0
- package/scripts/runners/run-deepseek.sh +7 -0
- package/scripts/runners/run-groq.sh +7 -0
- package/scripts/runners/run-mistral.sh +7 -0
- package/scripts/runners/run-openai-compat.sh +102 -0
- package/scripts/runners/run-openrouter.sh +5 -84
- package/scripts/runners/run-zai.sh +7 -0
|
@@ -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
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
|
|
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" "$@"
|