loki-mode 11.39.3 → 11.41.0
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/SKILL.md +5 -5
- package/VERSION +1 -1
- package/autonomy/lib/efficiency_cost.py +24 -0
- package/autonomy/route.sh +81 -21
- package/autonomy/run.sh +12 -3
- package/autonomy/trigger-server.py +62 -25
- package/bin/loki +1 -0
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +22 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/DEPLOYMENT.md +5 -3
- package/docs/INSTALLATION.md +1 -1
- package/docs/KNOWN-ISSUES.md +1 -1
- package/docs/exit-codes.md +0 -3
- package/docs/merge-queue.md +1 -1
- package/docs/sentry-intake.md +6 -6
- package/loki-ts/data/model-pricing.json +1 -0
- package/loki-ts/dist/loki.js +922 -922
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +218 -198
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-D4t9eA5j.js → AdminPage-P3gsF22s.js} +1 -1
- package/web-app/dist/assets/{Avatar-BMvmVYy3.js → Avatar-DfZ0kvq2.js} +1 -1
- package/web-app/dist/assets/{Badge-j7ETCF1w.js → Badge-C5fbiaZR.js} +1 -1
- package/web-app/dist/assets/{Button-Blavkzv4.js → Button-B5jGt7jZ.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-V6Ji2ITd.js → CockpitPage-BnpuQn_T.js} +1 -1
- package/web-app/dist/assets/{ComparePage-CBqk17CY.js → ComparePage-BwX4TQ41.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-C-E6orzu.js → ErrorBoundary-yB3DLU8x.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-rxNYJ9N-.js → EvidenceReceiptPanel-ZAI2-wq_.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-F31m3Aj_.js → GitHubIssuesPanel-DnKJAP_p.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-DHyZJE4y.js → GitHubPRsPanel-DB9k5ZWn.js} +1 -1
- package/web-app/dist/assets/{HomePage-BysZHe4l.js → HomePage-BXqw0kte.js} +2 -2
- package/web-app/dist/assets/{LoginPage-B1rXH3EO.js → LoginPage-YTq__thD.js} +1 -1
- package/web-app/dist/assets/{MagicPage-D_GRCJpO.js → MagicPage-cK4Voorh.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DLp1k4s-.js → MetricsPage-9GZEVtBC.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-L1YG0wb5.js → NotFoundPage-BFltgr29.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BFMWZp9h.js → ProjectPage-Dl1uGLpM.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DexfnMf5.js → ProjectsPage-B5C9Qp2r.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-D0U8Jy7j.js → SettingsPage-rZeN9P-3.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-vSg42BLH.js → ShowcasePage-CIpRNIwb.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-kJor0y66.js → SystemSettingsPage-DA21AT1n.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-qxjTX0fH.js → TeamsPage-Bfff6dlv.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-Dfntjiqk.js → TemplatesPage-COk_7uh-.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-D6xtYrBW.js → TerminalOutput-DcZ7Y8RN.js} +1 -1
- package/web-app/dist/assets/{activity-s480OdXm.js → activity-DwBipFux.js} +1 -1
- package/web-app/dist/assets/{bell-Dh2lHrTZ.js → bell-BNJ0XegR.js} +1 -1
- package/web-app/dist/assets/{bot-Dblq8THo.js → bot-BytqEOpz.js} +1 -1
- package/web-app/dist/assets/{check-B3kJ3BBC.js → check-DbTwoddF.js} +1 -1
- package/web-app/dist/assets/{chevron-left-t17IGfgp.js → chevron-left-CSsct9Tt.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DY9mDnl2.js → circle-alert-CS1P2iTs.js} +1 -1
- package/web-app/dist/assets/{clock-j7h1XCY-.js → clock-DCJ39VhK.js} +1 -1
- package/web-app/dist/assets/{cloud-DohoSLBp.js → cloud-_7nRyHTV.js} +1 -1
- package/web-app/dist/assets/{code-xml-DTGXMKpD.js → code-xml-DAftmEi4.js} +1 -1
- package/web-app/dist/assets/{database-CQH7dZj9.js → database-BoHhojPP.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-Dw7zuu-l.js → dollar-sign-CuaEpf1r.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-CICoYfYw.js → file-code-corner-D3C0H2eT.js} +1 -1
- package/web-app/dist/assets/{file-plus-DkdX4EaI.js → file-plus-DRmrq8_N.js} +1 -1
- package/web-app/dist/assets/{globe-C7dg3KOC.js → globe-Du5vCS0i.js} +1 -1
- package/web-app/dist/assets/{hammer-D1uweQjC.js → hammer-DkfxwcLQ.js} +1 -1
- package/web-app/dist/assets/{index-D5LyAuYp.js → index-ZmKBwWdn.js} +3 -3
- package/web-app/dist/assets/{layers-BpNwSWsz.js → layers-CbdK-349.js} +1 -1
- package/web-app/dist/assets/{loader-circle-D_nWlzcC.js → loader-circle-D5ms6nnc.js} +1 -1
- package/web-app/dist/assets/{lock-tSL-496a.js → lock-BxC0fjGK.js} +1 -1
- package/web-app/dist/assets/{package-Dl2lz12B.js → package-DUSYFBey.js} +1 -1
- package/web-app/dist/assets/{plus-2KTRN0bG.js → plus-IXJ_Iw5l.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BRun0THB.js → refresh-cw-BsYeQhUs.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-Cs6_HAAN.js → rotate-ccw-ijMjH7vU.js} +1 -1
- package/web-app/dist/assets/{scroll-text-CwMqWnrv.js → scroll-text-CIy0owUs.js} +1 -1
- package/web-app/dist/assets/{server-B74yQ8bd.js → server-BIctaKaw.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BtlkYO24.js → shield-alert-BOn8ZRj9.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-DPAu2ToS.js → thumbs-up-BSq8ePaY.js} +1 -1
- package/web-app/dist/assets/{trash-2-CRTghV6p.js → trash-2-CzF3qiiR.js} +1 -1
- package/web-app/dist/assets/{trending-down-B3I7DqUM.js → trending-down-CQJ9PWzb.js} +1 -1
- package/web-app/dist/assets/{trending-up-C0wXKjbk.js → trending-up-DfTOaGYJ.js} +1 -1
- package/web-app/dist/assets/{upload-Ca7BK4wj.js → upload-B7LrdY0s.js} +1 -1
- package/web-app/dist/assets/{usePolling-geBPWeod.js → usePolling-CvyeIA-Q.js} +1 -1
- package/web-app/dist/assets/{user-DOlmlt1y.js → user-Dwe-VKy5.js} +1 -1
- package/web-app/dist/index.html +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Runs an autonomous software factory that knows what it is supposed to deliver and proves it did, with a signed receipt. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v11.
|
|
6
|
+
# Loki Mode v11.41.0
|
|
7
7
|
|
|
8
8
|
**Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
|
|
9
9
|
|
|
@@ -259,9 +259,9 @@ loki start --provider codex ./prd.json # GPT-5.3 Codex, degraded mode
|
|
|
259
259
|
loki start --provider cline ./prd.md # Cline CLI, degraded mode
|
|
260
260
|
loki start --provider aider ./prd.md # Aider (18+ providers), degraded mode
|
|
261
261
|
|
|
262
|
-
# Parallel
|
|
263
|
-
loki start ./prd.md --parallel
|
|
264
|
-
loki start 123 --ship
|
|
262
|
+
# Parallel and auto-merge (legacy loop only; the default engine refuses these flags)
|
|
263
|
+
loki start ./prd.md --parallel --engine legacy
|
|
264
|
+
loki start 123 --ship --engine legacy # Issue -> PR -> auto-merge (default engine: 'loki start 123' opens the PR, then 'loki merge-queue')
|
|
265
265
|
|
|
266
266
|
# Run any loki command inside the published Docker image, zero config (v7.45.0).
|
|
267
267
|
# Bind-mounts the current folder to /workspace so .loki state, resume, and
|
|
@@ -476,4 +476,4 @@ Implemented, planned and deprecated items, with the version each landed in: `ski
|
|
|
476
476
|
|
|
477
477
|
---
|
|
478
478
|
|
|
479
|
-
**v11.
|
|
479
|
+
**v11.41.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.
|
|
1
|
+
11.41.0
|
|
@@ -32,6 +32,7 @@ __all__ = [
|
|
|
32
32
|
"read_child_ledger",
|
|
33
33
|
"load_prices",
|
|
34
34
|
"price_from_tokens",
|
|
35
|
+
"inference_geo_multiplier",
|
|
35
36
|
"DEFAULT_PRICES_PATH",
|
|
36
37
|
]
|
|
37
38
|
|
|
@@ -48,6 +49,29 @@ DEFAULT_PRICES_PATH = os.path.join(
|
|
|
48
49
|
# small helpers (self-contained copies; proof-generator.py keeps its own)
|
|
49
50
|
# ---------------------------------------------------------------------------
|
|
50
51
|
|
|
52
|
+
# Price multiplier for LOKI_INFERENCE_GEO, read from the same file the TS gate
|
|
53
|
+
# reads (inference_geo_multipliers in loki-ts/data/model-pricing.json). Unset,
|
|
54
|
+
# global and unknown values are 1.0; an unreadable file falls back to 1.1 for
|
|
55
|
+
# "us" so a budget never silently under-counts.
|
|
56
|
+
MODEL_PRICING_PATH = os.path.join(_REPO_ROOT, "loki-ts", "data", "model-pricing.json")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def inference_geo_multiplier(env=None, pricing_path=None):
|
|
60
|
+
geo = ((env if env is not None else os.environ).get("LOKI_INFERENCE_GEO") or "").strip().lower()
|
|
61
|
+
if not geo:
|
|
62
|
+
return 1.0
|
|
63
|
+
table = None
|
|
64
|
+
try:
|
|
65
|
+
with open(pricing_path or MODEL_PRICING_PATH, "r") as f:
|
|
66
|
+
table = json.load(f).get("inference_geo_multipliers")
|
|
67
|
+
except Exception:
|
|
68
|
+
table = None
|
|
69
|
+
if not isinstance(table, dict):
|
|
70
|
+
table = {"us": 1.1}
|
|
71
|
+
m = table.get(geo)
|
|
72
|
+
return float(m) if isinstance(m, (int, float)) and m > 0 else 1.0
|
|
73
|
+
|
|
74
|
+
|
|
51
75
|
def _read_json(path, default=None):
|
|
52
76
|
try:
|
|
53
77
|
with open(path, "r") as f:
|
package/autonomy/route.sh
CHANGED
|
@@ -4,20 +4,49 @@
|
|
|
4
4
|
# order and input form never change the engine:
|
|
5
5
|
# engine10 is the default for a PRD file, an issue ref, a multi-word task and a
|
|
6
6
|
# one-word brief, whether the flags come first or last.
|
|
7
|
-
# The legacy engine runs only on --engine legacy / LOKI_ENGINE=legacy, or
|
|
8
|
-
#
|
|
7
|
+
# The legacy engine runs only on --engine legacy / LOKI_ENGINE=legacy, or a size or
|
|
8
|
+
# env-provider fallback. A flag never changes the engine: engine10 maps it or refuses it.
|
|
9
9
|
# Pure functions: no exec, no side effects except R_* globals and the printers.
|
|
10
10
|
# Bash 3.2 compatible (no associative arrays, no ${var,,}).
|
|
11
11
|
|
|
12
12
|
# Flags that take a separate value token.
|
|
13
|
-
_ROUTE_VALUE_FLAGS=" --provider --budget --budget-limit --max-cost --max-iterations --max-retries --session-model --completion-promise --base-wait --max-wait --prd --brief --attempts --spec --aider-model --aider-flags --cline-model --isolation --output --engine --mirofish-rounds --mirofish-timeout "
|
|
13
|
+
_ROUTE_VALUE_FLAGS=" --provider --budget --budget-limit --max-cost --max-iterations --max-retries --session-model --completion-promise --base-wait --max-wait --prd --brief --attempts --spec --aider-model --aider-flags --cline-model --isolation --output --engine --mirofish-rounds --mirofish-timeout --max-duration --log-level --compliance --cost --remote --issue --bmad-project --openspec --mirofish-docker --destination --domain --env-file --health-url --health-match "
|
|
14
14
|
# Flags engine10 honors as-is.
|
|
15
|
-
_ROUTE_E10_FLAGS=" --no-pr --deep --json --verbose --provider --max-cost --spec --attempts "
|
|
15
|
+
_ROUTE_E10_FLAGS=" --no-pr --deep --json --verbose --quiet --resume --provider --max-cost --spec --attempts "
|
|
16
|
+
# The most a run cap can reach (capCeilingS(true) in loki-ts/src/util/run_cap.ts: the subscription ceiling).
|
|
17
|
+
_ROUTE_CAP_CEILING_S=3600
|
|
16
18
|
# Accepted and dropped (no-ops on a non-interactive run).
|
|
17
|
-
|
|
19
|
+
# --pr is a no-op because engine10 opens a PR by default (--no-pr turns it off).
|
|
20
|
+
_ROUTE_NOOP_FLAGS=" --yes -y --no-plan --no-mirofish --no-dashboard --pr "
|
|
21
|
+
|
|
22
|
+
# _route_refusal_hint FLAG: the engine10 replacement for a legacy-only flag (no engine10 equivalent exists).
|
|
23
|
+
_route_refusal_hint() {
|
|
24
|
+
case "$1" in
|
|
25
|
+
--ship) echo "engine10 opens the PR itself and does not auto-merge; merge it with 'loki merge-queue', or pass --engine legacy to keep --ship" ;;
|
|
26
|
+
--worktree|-w) echo "engine10 runs each attempt in its own isolated worktree already; drop the flag, or pass --engine legacy for a git-worktree run" ;;
|
|
27
|
+
--detach|-d) echo "run it in the background yourself ('nohup loki start ... &') or queue it with 'loki queue run', or pass --engine legacy for --detach" ;;
|
|
28
|
+
--parallel) echo "use 'loki queue run --parallel K' or 'loki issues run --parallel K' for parallel runs, or pass --engine legacy for --parallel" ;;
|
|
29
|
+
*) echo "drop it, or pass --engine legacy to run the legacy loop with it" ;;
|
|
30
|
+
esac
|
|
31
|
+
}
|
|
18
32
|
|
|
19
33
|
_route_has() { case "$1" in *" $2 "*) return 0 ;; esac; return 1; }
|
|
20
34
|
|
|
35
|
+
# _route_duration_s VALUE: seconds from 90, 90s, 90m or 2h; empty output when unusable or zero.
|
|
36
|
+
_route_duration_s() {
|
|
37
|
+
local v="$1" n unit
|
|
38
|
+
case "$v" in
|
|
39
|
+
[0-9]*[0-9]|[0-9]) n="$v"; unit=s ;;
|
|
40
|
+
[0-9]*[smh]) n="${v%?}"; unit="${v#"$n"}" ;;
|
|
41
|
+
*) return 0 ;;
|
|
42
|
+
esac
|
|
43
|
+
case "$n" in *[!0-9]*|"") return 0 ;; esac
|
|
44
|
+
n=$((10#$n))
|
|
45
|
+
[ "$n" -gt 0 ] || return 0
|
|
46
|
+
case "$unit" in m) n=$((n * 60)) ;; h) n=$((n * 3600)) ;; esac
|
|
47
|
+
printf '%s' "$n"
|
|
48
|
+
}
|
|
49
|
+
|
|
21
50
|
_route_json_str() {
|
|
22
51
|
printf '%s' "$1" | tr '\n\t\r' ' ' | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
|
|
23
52
|
}
|
|
@@ -45,9 +74,9 @@ loki_route_resolve() {
|
|
|
45
74
|
local verb="$1"; shift
|
|
46
75
|
R_DECIDED=0; R_E10=0; R_HARD=0; R_ENGINE=""; R_REASON=""; R_INPUT_TYPE=""; R_INPUT=""
|
|
47
76
|
R_PROVIDER=""; R_MODEL=""; R_NOTICE=""; R_ERR=""; R_EXPLAIN=0; R_JSON=0; R_SESSION_MODEL=""; R_VERB=""
|
|
48
|
-
R_E10_ARGS=(); R_CLEAN=(); R_ADAPTER=""; R_CAPDIFF=()
|
|
77
|
+
R_E10_ARGS=(); R_CLEAN=(); R_ADAPTER=""; R_CAPDIFF=(); R_E10_CAP_S=""; R_DRY=0; R_MAXCOST=""
|
|
49
78
|
|
|
50
|
-
local a engine_req="" help=0 legacy_flag="" session_model="" provider_flag=""
|
|
79
|
+
local a engine_req="" dry=0 help=0 legacy_flag="" session_model="" provider_flag="" max_duration="" cap_err="" input_flag=""
|
|
51
80
|
local -a positionals=() passthru=()
|
|
52
81
|
local i=0 n=$#
|
|
53
82
|
local -a argv=("$@")
|
|
@@ -73,15 +102,21 @@ loki_route_resolve() {
|
|
|
73
102
|
fi
|
|
74
103
|
fi
|
|
75
104
|
case "$name" in
|
|
76
|
-
--prd) positionals+=("$val"); continue ;;
|
|
77
|
-
--brief) positionals+=("$val"); continue ;;
|
|
105
|
+
--prd|--brief) input_flag="$name"; positionals+=("$val"); continue ;;
|
|
78
106
|
--provider) provider_flag="$val"; passthru+=(--provider "$val"); continue ;;
|
|
79
107
|
--session-model) session_model="$val"; continue ;;
|
|
80
|
-
--budget|--budget-limit|--max-cost) passthru+=(--max-cost "$val"); continue ;;
|
|
108
|
+
--budget|--budget-limit|--max-cost) passthru+=(--max-cost "$val"); R_MAXCOST="$val"; continue ;;
|
|
109
|
+
--dry-run) dry=1; continue ;;
|
|
81
110
|
--json) R_JSON=1; passthru+=(--json); continue ;;
|
|
82
111
|
-v) passthru+=(--verbose); continue ;;
|
|
83
112
|
--attempts) passthru+=(--attempts "$val"); continue ;;
|
|
84
113
|
--spec) passthru+=(--spec "$val"); continue ;;
|
|
114
|
+
--max-duration)
|
|
115
|
+
max_duration="$(_route_duration_s "$val")"
|
|
116
|
+
if [ -z "$max_duration" ] && [ -z "$cap_err" ]; then
|
|
117
|
+
cap_err="loki: --max-duration '$val' is not a duration (use seconds, or 90m / 2h)"
|
|
118
|
+
fi
|
|
119
|
+
continue ;;
|
|
85
120
|
esac
|
|
86
121
|
if _route_has "$_ROUTE_NOOP_FLAGS" "$name"; then continue; fi
|
|
87
122
|
if _route_has "$_ROUTE_E10_FLAGS" "$name"; then passthru+=("$name"); continue; fi
|
|
@@ -131,10 +166,10 @@ loki_route_resolve() {
|
|
|
131
166
|
task|issue) ;;
|
|
132
167
|
*) R_INPUT_TYPE=""; return 0 ;;
|
|
133
168
|
esac
|
|
134
|
-
if [ -n "$legacy_flag" ] && [ -z "$engine_req" ]; then R_INPUT_TYPE=""; return 0; fi
|
|
135
169
|
fi
|
|
136
170
|
|
|
137
171
|
R_DECIDED=1
|
|
172
|
+
if [ -n "$cap_err" ]; then R_ERR="$cap_err"; return 0; fi
|
|
138
173
|
if [ "$R_INPUT_TYPE" = "missing-prd" ]; then
|
|
139
174
|
R_ERR="loki: PRD file not found: ${positionals[0]}"
|
|
140
175
|
return 0
|
|
@@ -177,19 +212,39 @@ loki_route_resolve() {
|
|
|
177
212
|
if [ -n "$task" ]; then R_E10_ARGS+=("$task"); fi
|
|
178
213
|
R_E10_ARGS+=("${passthru[@]+"${passthru[@]}"}")
|
|
179
214
|
|
|
215
|
+
# --prd and --brief name the input themselves; a second input would have glued its words into the task.
|
|
216
|
+
if [ -n "$input_flag" ] && [ "$npos" -gt 1 ]; then
|
|
217
|
+
R_ERR="loki: $input_flag cannot be combined with another input (${positionals[*]}); give one input"
|
|
218
|
+
return 0
|
|
219
|
+
fi
|
|
220
|
+
# A flag never changes the engine (#236): an unmapped one is refused, not routed to legacy.
|
|
221
|
+
if [ -n "$legacy_flag" ] && [ "$engine_req" != "legacy" ]; then
|
|
222
|
+
R_ERR="loki: flag $legacy_flag is not supported by the Loki 10 engine; $(_route_refusal_hint "$legacy_flag")"
|
|
223
|
+
return 0
|
|
224
|
+
fi
|
|
225
|
+
# Wall-clock cap: LOKI_E10_CAP_S seconds, bounded by the run-cap ceiling.
|
|
226
|
+
if [ -n "$max_duration" ] && [ "$engine_req" != "legacy" ]; then
|
|
227
|
+
R_E10_CAP_S="$max_duration"
|
|
228
|
+
if [ "$R_E10_CAP_S" -gt "$_ROUTE_CAP_CEILING_S" ]; then
|
|
229
|
+
R_E10_CAP_S="$_ROUTE_CAP_CEILING_S"
|
|
230
|
+
R_NOTICE="loki: --max-duration $max_duration s is above the engine10 run-cap ceiling; using ${_ROUTE_CAP_CEILING_S}s."
|
|
231
|
+
fi
|
|
232
|
+
fi
|
|
233
|
+
if [ -n "$provider_flag" ] && [ "$engine_req" != "legacy" ]; then
|
|
234
|
+
case "$provider_flag" in
|
|
235
|
+
claude|codex|cline|aider|opencode) ;;
|
|
236
|
+
*)
|
|
237
|
+
R_ERR="loki: --provider $provider_flag has no Loki 10 engine invoker (use claude, codex, cline, aider or opencode, or pass --engine legacy)"
|
|
238
|
+
return 0 ;;
|
|
239
|
+
esac
|
|
240
|
+
fi
|
|
241
|
+
# --dry-run (engine10 has no preview of its own for these inputs): print the route, then exit 0 without a run.
|
|
242
|
+
if [ "$dry" = "1" ] && [ "$engine_req" != "legacy" ]; then R_DRY=1; fi
|
|
180
243
|
local why=""
|
|
181
244
|
if [ "$engine_req" = "legacy" ]; then
|
|
182
245
|
R_ENGINE=legacy; R_REASON="explicit: --engine legacy or LOKI_ENGINE=legacy"
|
|
183
246
|
elif [ "$engine_req" = "engine10" ]; then
|
|
184
|
-
if [ -n "$legacy_flag" ]; then
|
|
185
|
-
R_ERR="loki: flag $legacy_flag is not supported by the engine10 engine; drop it or use --engine legacy"
|
|
186
|
-
return 0
|
|
187
|
-
fi
|
|
188
247
|
R_ENGINE=engine10; R_E10=1; R_HARD=1; R_REASON="explicit: --engine engine10"
|
|
189
|
-
elif [ -n "$legacy_flag" ]; then
|
|
190
|
-
R_ENGINE=legacy
|
|
191
|
-
R_REASON="flag $legacy_flag is not supported by engine10"
|
|
192
|
-
R_NOTICE="loki: routing this call to the legacy engine because of $legacy_flag (engine10 does not support it). Drop the flag to use engine10, or pass --engine legacy to silence this."
|
|
193
248
|
else
|
|
194
249
|
case "$R_PROVIDER" in
|
|
195
250
|
claude|codex|cline|aider|opencode) ;;
|
|
@@ -245,9 +300,9 @@ loki_route_print() {
|
|
|
245
300
|
for d in ${R_CAPDIFF[@]+"${R_CAPDIFF[@]}"}; do
|
|
246
301
|
diffs="${diffs:+$diffs,}\"$(_route_json_str "$d")\""
|
|
247
302
|
done
|
|
248
|
-
printf '{"engine":"%s","adapter":"%s","provider":"%s","model":"%s","input_type":"%s","input":"%s","reason":"%s","capability_differences":[%s]}\n' \
|
|
303
|
+
printf '{"engine":"%s","adapter":"%s","provider":"%s","model":"%s","input_type":"%s","input":"%s","reason":"%s","capability_differences":[%s],"run_cap_s":%s}\n' \
|
|
249
304
|
"$(_route_json_str "$R_ENGINE")" "$(_route_json_str "$R_ADAPTER")" "$(_route_json_str "$R_PROVIDER")" "$(_route_json_str "$R_MODEL")" \
|
|
250
|
-
"$(_route_json_str "$R_INPUT_TYPE")" "$(_route_json_str "$shown")" "$(_route_json_str "$R_REASON")" "$diffs"
|
|
305
|
+
"$(_route_json_str "$R_INPUT_TYPE")" "$(_route_json_str "$shown")" "$(_route_json_str "$R_REASON")" "$diffs" "${R_E10_CAP_S:-null}"
|
|
251
306
|
else
|
|
252
307
|
printf 'engine: %s\nadapter: %s\nprovider: %s\nmodel: %s\ninput: %s (%s)\nreason: %s\n' \
|
|
253
308
|
"$R_ENGINE" "$R_ADAPTER" "$R_PROVIDER" "$R_MODEL" "$R_INPUT_TYPE" "$shown" "$R_REASON"
|
|
@@ -296,6 +351,11 @@ loki_route_dispatch() {
|
|
|
296
351
|
if [ "$R_DECIDED" != "1" ]; then return 0; fi
|
|
297
352
|
if [ -n "$R_ERR" ]; then echo "$R_ERR" >&2; return 8; fi
|
|
298
353
|
if [ "$R_EXPLAIN" = "1" ]; then loki_route_print; return 7; fi
|
|
354
|
+
if [ "$R_DRY" = "1" ]; then
|
|
355
|
+
loki_route_print
|
|
356
|
+
printf 'max-cost: %s\nrun-cap: %ss\ndry-run: nothing was started\n' "${R_MAXCOST:-default (engine10 resolves its own)}" "${R_E10_CAP_S:-$_ROUTE_CAP_CEILING_S}"
|
|
357
|
+
return 7
|
|
358
|
+
fi
|
|
299
359
|
if [ -n "$R_NOTICE" ]; then echo "$R_NOTICE" >&2; fi
|
|
300
360
|
R_VERB="$verb"
|
|
301
361
|
return 0
|
package/autonomy/run.sh
CHANGED
|
@@ -20502,8 +20502,16 @@ check_budget_limit() {
|
|
|
20502
20502
|
# Calculate cost from per-iteration efficiency files (same source as /api/cost)
|
|
20503
20503
|
if [ -d "$efficiency_dir" ]; then
|
|
20504
20504
|
current_cost=$(python3 -c "
|
|
20505
|
-
import json, glob
|
|
20505
|
+
import json, glob, os, sys
|
|
20506
20506
|
total = 0.0
|
|
20507
|
+
# LOKI_INFERENCE_GEO multiplier on token-priced records, from the same JSON the
|
|
20508
|
+
# TS gate reads (autonomy/lib/efficiency_cost.py); the fallback keeps us at 1.1.
|
|
20509
|
+
try:
|
|
20510
|
+
sys.path.insert(0, '${SCRIPT_DIR}/lib')
|
|
20511
|
+
from efficiency_cost import inference_geo_multiplier
|
|
20512
|
+
geo = inference_geo_multiplier()
|
|
20513
|
+
except Exception:
|
|
20514
|
+
geo = 1.1 if os.environ.get('LOKI_INFERENCE_GEO', '').strip().lower() == 'us' else 1.0
|
|
20507
20515
|
pricing = {
|
|
20508
20516
|
'fable': {'input': 10.00, 'output': 50.00, 'cache_read': 0.25, 'cache_write': 12.5, 'cache_write_1h': 20},
|
|
20509
20517
|
'claude-fable-5': {'input': 10.00, 'output': 50.00, 'cache_read': 0.25, 'cache_write': 12.5, 'cache_write_1h': 20},
|
|
@@ -20544,8 +20552,9 @@ for f in glob.glob('${efficiency_dir}/*.json'):
|
|
|
20544
20552
|
# same run reports two different spends.
|
|
20545
20553
|
cr = d.get('cache_read_tokens', 0) or 0
|
|
20546
20554
|
cw = d.get('cache_creation_tokens', 0) or 0
|
|
20547
|
-
|
|
20548
|
-
|
|
20555
|
+
rec = (inp / 1_000_000) * p['input'] + (out / 1_000_000) * p['output']
|
|
20556
|
+
rec += (cr / 1_000_000) * p.get('cache_read', p['input'] * 0.1) + (cw / 1_000_000) * p.get('cache_write', p['input'] * 1.25)
|
|
20557
|
+
total += rec * geo
|
|
20549
20558
|
except: pass
|
|
20550
20559
|
print(round(total, 4))
|
|
20551
20560
|
" 2>/dev/null || echo "0")
|
|
@@ -29,7 +29,7 @@ every /jobs request is rejected with 503 and an audit log line.
|
|
|
29
29
|
Self-healing entry point: POST /sentry accepts a Sentry integration webhook
|
|
30
30
|
authenticated by Sentry's own HMAC (sentry-hook-signature) under a THIRD,
|
|
31
31
|
separate secret (LOKI_SENTRY_WEBHOOK_SECRET or SENTRY_CLIENT_SECRET). A valid
|
|
32
|
-
alert enqueues `loki start "<normalized brief>" --pr
|
|
32
|
+
alert enqueues `loki start "<normalized brief>" --pr`: the output is a
|
|
33
33
|
receipt-gated PR only, never a deploy. No secret means the route answers 503.
|
|
34
34
|
|
|
35
35
|
Usage:
|
|
@@ -268,9 +268,9 @@ def constant_time_equals(a, b):
|
|
|
268
268
|
|
|
269
269
|
|
|
270
270
|
# How long to wait for a dispatched `loki start` to finish before we stop
|
|
271
|
-
# waiting on it. The
|
|
272
|
-
#
|
|
273
|
-
#
|
|
271
|
+
# waiting on it. The start runs in the foreground on the Loki 10 engine; this bound only
|
|
272
|
+
# stops the worker thread waiting on a long run. The child keeps running and
|
|
273
|
+
# is reaped in the background after we stop waiting.
|
|
274
274
|
DISPATCH_WAIT_SECONDS = 30
|
|
275
275
|
|
|
276
276
|
# Defaults for the bounded worker queue.
|
|
@@ -445,6 +445,32 @@ def send_notification(message):
|
|
|
445
445
|
pass
|
|
446
446
|
|
|
447
447
|
|
|
448
|
+
def _dispatch_log_paths():
|
|
449
|
+
"""Fresh stdout and stderr log paths for one dispatch under .loki/triggers."""
|
|
450
|
+
paths = []
|
|
451
|
+
for suffix in (".out", ".err"):
|
|
452
|
+
fd, path = tempfile.mkstemp(prefix="dispatch-", suffix=suffix, dir=str(get_loki_dir()))
|
|
453
|
+
os.close(fd)
|
|
454
|
+
paths.append(path)
|
|
455
|
+
return paths
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _read_bytes(path):
|
|
459
|
+
try:
|
|
460
|
+
with open(path, "rb") as f:
|
|
461
|
+
return f.read()
|
|
462
|
+
except OSError:
|
|
463
|
+
return b""
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def _remove_quietly(*paths):
|
|
467
|
+
for path in paths:
|
|
468
|
+
try:
|
|
469
|
+
os.unlink(path)
|
|
470
|
+
except OSError:
|
|
471
|
+
pass
|
|
472
|
+
|
|
473
|
+
|
|
448
474
|
def _reap_child(proc):
|
|
449
475
|
"""Wait on a child process so it is always reaped (no zombie).
|
|
450
476
|
|
|
@@ -514,29 +540,34 @@ def run_loki_outcome(args, dry_run=False, stdout_sink=None, extra_env=None):
|
|
|
514
540
|
logging.info("[DRY-RUN] Would run: %s", " ".join(cmd))
|
|
515
541
|
return OUTCOME_PASSED
|
|
516
542
|
logging.info("Running: %s", " ".join(cmd))
|
|
543
|
+
# Child output goes to per-run files, never a pipe: past the wait window
|
|
544
|
+
# nothing reads a pipe, so a child writing more than the ~64KB pipe buffer
|
|
545
|
+
# would block forever. The files double as the run log for a detached child.
|
|
546
|
+
out_path, err_path = _dispatch_log_paths()
|
|
517
547
|
try:
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
548
|
+
with open(out_path, "wb") as out_f, open(err_path, "wb") as err_f:
|
|
549
|
+
proc = subprocess.Popen(
|
|
550
|
+
cmd,
|
|
551
|
+
stdout=out_f,
|
|
552
|
+
stderr=err_f,
|
|
553
|
+
env=_scoped_child_env(extra_env),
|
|
554
|
+
)
|
|
524
555
|
except (FileNotFoundError, OSError) as e:
|
|
525
556
|
logging.error("Failed to launch %s: %s", " ".join(cmd), e)
|
|
557
|
+
_remove_quietly(out_path, err_path)
|
|
526
558
|
return OUTCOME_FAILED
|
|
527
559
|
|
|
528
560
|
try:
|
|
529
|
-
|
|
530
|
-
if stdout_sink is not None:
|
|
531
|
-
stdout_sink.append((stdout or b"").decode("utf-8", errors="replace"))
|
|
561
|
+
proc.wait(timeout=DISPATCH_WAIT_SECONDS)
|
|
532
562
|
except subprocess.TimeoutExpired:
|
|
533
563
|
# Detached past the wait window. The reaper collects the child, but we
|
|
534
564
|
# never see its exit code, so the outcome is genuinely UNKNOWN -- NOT a
|
|
535
565
|
# pass. Reporting success here is exactly the defect this replaces.
|
|
536
566
|
logging.info(
|
|
537
|
-
"Dispatch pid=%d still running after %ds; reaping in background",
|
|
567
|
+
"Dispatch pid=%d still running after %ds; reaping in background, output in %s",
|
|
538
568
|
proc.pid,
|
|
539
569
|
DISPATCH_WAIT_SECONDS,
|
|
570
|
+
out_path,
|
|
540
571
|
)
|
|
541
572
|
threading.Thread(
|
|
542
573
|
target=_reap_child,
|
|
@@ -546,6 +577,12 @@ def run_loki_outcome(args, dry_run=False, stdout_sink=None, extra_env=None):
|
|
|
546
577
|
).start()
|
|
547
578
|
return OUTCOME_UNKNOWN
|
|
548
579
|
|
|
580
|
+
stdout = _read_bytes(out_path)
|
|
581
|
+
stderr = _read_bytes(err_path)
|
|
582
|
+
_remove_quietly(out_path, err_path)
|
|
583
|
+
if stdout_sink is not None:
|
|
584
|
+
stdout_sink.append(stdout.decode("utf-8", errors="replace"))
|
|
585
|
+
|
|
549
586
|
if proc.returncode == 0:
|
|
550
587
|
logging.info("Dispatch pid=%d completed (exit 0)", proc.pid)
|
|
551
588
|
return OUTCOME_PASSED
|
|
@@ -778,7 +815,7 @@ def tracker_comment_steer(kind, payload, is_live, dry_run=False):
|
|
|
778
815
|
|
|
779
816
|
|
|
780
817
|
def handle_issues_event(payload, dry_run=False):
|
|
781
|
-
"""Handle issues event: opened -> loki start <issue-ref> --pr
|
|
818
|
+
"""Handle issues event: opened -> loki start <issue-ref> --pr."""
|
|
782
819
|
action = payload.get("action", "")
|
|
783
820
|
if action != "opened":
|
|
784
821
|
return None, "skipped (action=%s)" % action
|
|
@@ -801,7 +838,7 @@ def handle_issues_event(payload, dry_run=False):
|
|
|
801
838
|
ref = str(issue_number)
|
|
802
839
|
if repo_full_name:
|
|
803
840
|
ref = "%s#%s" % (repo_full_name, issue_number)
|
|
804
|
-
args = ["start", ref, "--pr"
|
|
841
|
+
args = ["start", ref, "--pr"]
|
|
805
842
|
summary = "issue #%s opened in %s" % (issue_number, repo_full_name)
|
|
806
843
|
success = run_loki_command(args, dry_run=dry_run)
|
|
807
844
|
status = "fired" if success else "error"
|
|
@@ -811,7 +848,7 @@ def handle_issues_event(payload, dry_run=False):
|
|
|
811
848
|
|
|
812
849
|
|
|
813
850
|
def handle_pull_request_event(payload, dry_run=False):
|
|
814
|
-
"""Handle pull_request event: synchronize -> loki start <pr-ref
|
|
851
|
+
"""Handle pull_request event: synchronize -> loki start <pr-ref>."""
|
|
815
852
|
action = payload.get("action", "")
|
|
816
853
|
if action != "synchronize":
|
|
817
854
|
return None, "skipped (action=%s)" % action
|
|
@@ -828,7 +865,7 @@ def handle_pull_request_event(payload, dry_run=False):
|
|
|
828
865
|
ref = str(pr_number)
|
|
829
866
|
if repo_full_name:
|
|
830
867
|
ref = "%s#%s" % (repo_full_name, pr_number)
|
|
831
|
-
args = ["start", ref
|
|
868
|
+
args = ["start", ref]
|
|
832
869
|
summary = "PR #%s synchronized in %s" % (pr_number, repo_full_name)
|
|
833
870
|
success = run_loki_command(args, dry_run=dry_run)
|
|
834
871
|
status = "fired" if success else "error"
|
|
@@ -852,7 +889,7 @@ def handle_workflow_run_event(payload, dry_run=False):
|
|
|
852
889
|
summary = "workflow '%s' failed in %s" % (wf_name, repo_full_name)
|
|
853
890
|
# CI-failure context: re-run the current spec in the working directory so
|
|
854
891
|
# the agent can repair the failing build. No issue/PR ref to attach here.
|
|
855
|
-
args = ["start"
|
|
892
|
+
args = ["start"]
|
|
856
893
|
success = run_loki_command(args, dry_run=dry_run)
|
|
857
894
|
status = "fired" if success else "error"
|
|
858
895
|
if success:
|
|
@@ -862,14 +899,14 @@ def handle_workflow_run_event(payload, dry_run=False):
|
|
|
862
899
|
|
|
863
900
|
def brief_start_args(brief):
|
|
864
901
|
"""argv for a delegated PR run. `--brief` forces brief mode so the text is
|
|
865
|
-
never reclassified as a PRD path or issue URL, and `--pr
|
|
902
|
+
never reclassified as a PRD path or issue URL, and `--pr` are only
|
|
866
903
|
honored by `loki start` in brief mode because cmd_start routes them through
|
|
867
904
|
the worktree + PR path."""
|
|
868
|
-
return ["start", "--brief", brief, "--pr"
|
|
905
|
+
return ["start", "--brief", brief, "--pr"]
|
|
869
906
|
|
|
870
907
|
|
|
871
908
|
def handle_job_event(payload, dry_run=False):
|
|
872
|
-
"""Handle a remotely-submitted job: loki start <spec
|
|
909
|
+
"""Handle a remotely-submitted job: loki start <spec>.
|
|
873
910
|
|
|
874
911
|
Runs on the same worker pool as the webhook handlers. The spec was already
|
|
875
912
|
validated by valid_spec() at admission; it is re-checked here so this
|
|
@@ -890,7 +927,7 @@ def handle_job_event(payload, dry_run=False):
|
|
|
890
927
|
elif payload.get("pr") is True:
|
|
891
928
|
args = brief_start_args(spec.strip())
|
|
892
929
|
else:
|
|
893
|
-
args = ["start", spec.strip()
|
|
930
|
+
args = ["start", spec.strip()]
|
|
894
931
|
summary = "job %s: %s" % (payload.get("job_id", "?"), spec.strip())
|
|
895
932
|
# A remote submitter gates CI on this, so report the BUILD's outcome, not
|
|
896
933
|
# merely that a build was launched. "fired" (launched) and "passed" must
|
|
@@ -1338,7 +1375,7 @@ def build_sentry_brief(norm, payload=None):
|
|
|
1338
1375
|
|
|
1339
1376
|
|
|
1340
1377
|
def handle_sentry_event(payload, dry_run=False):
|
|
1341
|
-
"""Handle a verified Sentry alert: loki start <brief> --pr
|
|
1378
|
+
"""Handle a verified Sentry alert: loki start <brief> --pr.
|
|
1342
1379
|
|
|
1343
1380
|
PR only. Never passes a deploy argument: a fix still has to earn a VERIFIED
|
|
1344
1381
|
receipt, and shipping it stays a separate, gated human step.
|
|
@@ -1535,7 +1572,7 @@ class Dispatcher:
|
|
|
1535
1572
|
borrowed-receipt failure this design exists to prevent.
|
|
1536
1573
|
|
|
1537
1574
|
Attribution is deliberately NOT resolved when the dispatch returns.
|
|
1538
|
-
`loki start
|
|
1575
|
+
`loki start` can outlast the dispatch wait window, and the
|
|
1539
1576
|
build runs for minutes and writes its receipt at the very end -- so a
|
|
1540
1577
|
window closed at dispatch-return would always see an unchanged pointer
|
|
1541
1578
|
and every real build would 404. Resolution happens lazily in
|
package/bin/loki
CHANGED
|
@@ -635,6 +635,7 @@ if [ -f "$REPO_ROOT/autonomy/route.sh" ] && { [ "$_LOKI_START_ATTEMPTS" != "1" ]
|
|
|
635
635
|
case "$R_SESSION_MODEL" in small) R_SESSION_MODEL=fast ;; medium) R_SESSION_MODEL=development ;; high) R_SESSION_MODEL=planning ;; esac
|
|
636
636
|
export LOKI_SESSION_MODEL="$R_SESSION_MODEL"
|
|
637
637
|
fi
|
|
638
|
+
if [ "$R_E10" = "1" ] && [ -n "${R_E10_CAP_S:-}" ]; then export LOKI_E10_CAP_S="$R_E10_CAP_S"; fi
|
|
638
639
|
if [ "$R_E10" != "1" ]; then
|
|
639
640
|
set -- "$([ "$R_VERB" = "bare" ] && echo start || echo "$R_VERB")" ${R_CLEAN[@]+"${R_CLEAN[@]}"}
|
|
640
641
|
fi
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -7830,6 +7830,25 @@ def _record_is_measured(rec: Any) -> bool:
|
|
|
7830
7830
|
return False
|
|
7831
7831
|
|
|
7832
7832
|
|
|
7833
|
+
def _inference_geo_multiplier() -> float:
|
|
7834
|
+
"""LOKI_INFERENCE_GEO price multiplier. Mirrors inference_geo_multiplier() in
|
|
7835
|
+
autonomy/lib/efficiency_cost.py (same JSON key, us falls back to 1.1); kept as
|
|
7836
|
+
a local copy for the same reason as _MEASURED_FIELDS."""
|
|
7837
|
+
geo = (os.environ.get("LOKI_INFERENCE_GEO") or "").strip().lower()
|
|
7838
|
+
if not geo:
|
|
7839
|
+
return 1.0
|
|
7840
|
+
table = None
|
|
7841
|
+
try:
|
|
7842
|
+
path = _Path(__file__).resolve().parent.parent / "loki-ts" / "data" / "model-pricing.json"
|
|
7843
|
+
table = json.loads(path.read_text()).get("inference_geo_multipliers")
|
|
7844
|
+
except Exception:
|
|
7845
|
+
table = None
|
|
7846
|
+
if not isinstance(table, dict):
|
|
7847
|
+
table = {"us": 1.1}
|
|
7848
|
+
m = table.get(geo)
|
|
7849
|
+
return float(m) if isinstance(m, (int, float)) and m > 0 else 1.0
|
|
7850
|
+
|
|
7851
|
+
|
|
7833
7852
|
def _calculate_model_cost(
|
|
7834
7853
|
model: str,
|
|
7835
7854
|
input_tokens: int,
|
|
@@ -7856,7 +7875,9 @@ def _calculate_model_cost(
|
|
|
7856
7875
|
output_cost = (output_tokens / 1_000_000) * pricing.get("output", 15.00)
|
|
7857
7876
|
cache_read_cost = (cache_read_tokens / 1_000_000) * pricing.get("cache_read", inp_rate * 0.1)
|
|
7858
7877
|
cache_write_cost = (cache_creation_tokens / 1_000_000) * pricing.get("cache_write", inp_rate * 1.25)
|
|
7859
|
-
return round(
|
|
7878
|
+
return round(
|
|
7879
|
+
(input_cost + output_cost + cache_read_cost + cache_write_cost) * _inference_geo_multiplier(), 6
|
|
7880
|
+
)
|
|
7860
7881
|
|
|
7861
7882
|
|
|
7862
7883
|
@app.get("/api/cost", dependencies=[Depends(auth.require_scope("read"))])
|
package/docs/CLI-REFERENCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CLI reference
|
|
2
2
|
|
|
3
|
-
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.
|
|
3
|
+
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.41.0. Do not edit by hand.
|
|
4
4
|
Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
|
|
5
5
|
|
|
6
6
|
| Command | Description |
|
package/docs/DEPLOYMENT.md
CHANGED
|
@@ -119,9 +119,11 @@ logged and ignored.
|
|
|
119
119
|
|
|
120
120
|
| Event | Action | What runs |
|
|
121
121
|
|---|---|---|
|
|
122
|
-
| `issues` | `opened` | `loki start owner/repo#N --pr
|
|
123
|
-
| `pull_request` | `synchronize` | `loki start owner/repo#N
|
|
124
|
-
| `workflow_run` | `completed` with `conclusion=failure` | `loki start
|
|
122
|
+
| `issues` | `opened` | `loki start owner/repo#N --pr` |
|
|
123
|
+
| `pull_request` | `synchronize` | `loki start owner/repo#N` |
|
|
124
|
+
| `workflow_run` | `completed` with `conclusion=failure` | `loki start` |
|
|
125
|
+
|
|
126
|
+
The trigger server runs each of these starts in the foreground on the Loki 10 engine (Wall and VERIFIED apply). A run longer than the dispatch wait window is reaped in the background and its job status stays unknown until it exits.
|
|
125
127
|
|
|
126
128
|
Note what is **not** there. Labelling an issue does nothing. Commenting on an
|
|
127
129
|
issue does nothing. Opening a pull request does nothing -- for PRs it is
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
|
|
4
4
|
|
|
5
|
-
**Version:** v11.
|
|
5
|
+
**Version:** v11.41.0
|
|
6
6
|
|
|
7
7
|
**Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
|
|
8
8
|
|
package/docs/KNOWN-ISSUES.md
CHANGED
|
@@ -4,7 +4,7 @@ Issues in the current release that are known and not yet fixed. Report new ones
|
|
|
4
4
|
|
|
5
5
|
## Which engine runs
|
|
6
6
|
|
|
7
|
-
From 11.4.0, `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine whatever the flag order or input form. The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, for a provider with no Loki 10 invoker, for a PRD over 100000 bytes, or
|
|
7
|
+
From 11.4.0, `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` run the Loki 10 engine whatever the flag order or input form. The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, for a provider with no Loki 10 invoker, for a PRD over 100000 bytes, or never because of a flag: a flag Loki 10 cannot honor (`--simple`, `--sandbox`, `--ship`, `--worktree`, `--detach`, `--parallel`, ...) is refused with exit 2 and names its replacement, and `--engine legacy` keeps it. `--pr` is accepted (Loki 10 opens the PR by default), `--quiet` and `--resume` are honored, and `--dry-run` prints the route, max-cost and run cap without starting. Check with `loki route start <args> --json`: it reports `engine`, `adapter`, `reason` and `capability_differences`. The full table is in the Routing contract section of `docs/exit-codes.md`.
|
|
8
8
|
|
|
9
9
|
## Exit codes
|
|
10
10
|
|
package/docs/exit-codes.md
CHANGED
|
@@ -455,13 +455,10 @@ The table below is rendered from live `loki route --json` output by `tests/test-
|
|
|
455
455
|
| `start p.md --provider cline` | engine10 | engine10:cline | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
456
456
|
| `start p.md --provider aider` | engine10 | engine10:aider | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
457
457
|
| `start p.md --provider opencode` | engine10 | engine10:opencode | 1 listed | default: prd input runs on engine10 regardless of flag order |
|
|
458
|
-
| `start p.md --provider gemini` | legacy | legacy-bash:gemini | 2 listed | provider gemini has no engine10 invoker (use claude, codex, cline, aider or opencode) |
|
|
459
458
|
| `start p.md --engine legacy` | legacy | legacy-bash:claude | 1 listed | explicit: --engine legacy or LOKI_ENGINE=legacy |
|
|
460
459
|
| `start --engine legacy p.md` | legacy | legacy-bash:claude | 1 listed | explicit: --engine legacy or LOKI_ENGINE=legacy |
|
|
461
460
|
| `LOKI_ENGINE=legacy start p.md` | legacy | legacy-bash:claude | 1 listed | explicit: --engine legacy or LOKI_ENGINE=legacy |
|
|
462
461
|
| `start p.md --engine engine10` | engine10 | engine10:claude | none | explicit: --engine engine10 |
|
|
463
462
|
| `LOKI_ENGINE=engine10 start p.md` | engine10 | engine10:claude | none | explicit: --engine engine10 |
|
|
464
|
-
| `start p.md --parallel` | legacy | legacy-bash:claude | 2 listed | flag --parallel is not supported by engine10 |
|
|
465
|
-
| `start --parallel p.md` | legacy | legacy-bash:claude | 2 listed | flag --parallel is not supported by engine10 |
|
|
466
463
|
| `start big.md` | legacy | legacy-bash:claude | 1 listed | PRD is larger than 100000 bytes (engine10 takes the task as one argument) |
|
|
467
464
|
<!-- route-table:end -->
|
package/docs/merge-queue.md
CHANGED
|
@@ -28,5 +28,5 @@ tail to a bounded repair session on the PR branch (LOKI_PR_REPAIR_CMD, default a
|
|
|
28
28
|
argument), pushes, and re-checks, up to LOKI_PR_REPAIR_MAX attempts (default 2).
|
|
29
29
|
Green goes through the same merge gate as `loki merge pr`. When attempts run out
|
|
30
30
|
the PR is returned to draft, nothing merges, and the last failure log is printed.
|
|
31
|
-
`loki start --ship` calls this after it opens the PR; `/merge watch <pr>` runs it
|
|
31
|
+
`loki start --ship --engine legacy` calls this after it opens the PR; `/merge watch <pr>` runs it
|
|
32
32
|
from `loki chat`.
|