ennodia 0.5.0 → 0.5.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/docs/reference/mcp-tools.md +2 -0
- package/docs/reference/supported-harnesses.md +2 -0
- package/package.json +1 -1
- package/src/core.ts +2 -2
- package/src/readiness.ts +10 -6
- package/src/version.ts +1 -1
|
@@ -732,6 +732,8 @@ After the worker settles, inspect its task receipt. If `canContinue` is true,
|
|
|
732
732
|
pass that task ID as `continueTaskId` in the next run. The follow-up keeps the
|
|
733
733
|
harness and directory. It inherits the model and reasoning effort unless you
|
|
734
734
|
supply new values. Each follow-up has a new task ID and execution allowance.
|
|
735
|
+
|
|
736
|
+
Readiness checks use the inherited or explicitly supplied model before the follow-up starts.
|
|
735
737
|
An earlier turn cannot be used once a follow-up has started.
|
|
736
738
|
|
|
737
739
|
Continuation requires a task still held by the same running Ennodia server.
|
|
@@ -147,7 +147,9 @@ Replace the key through the native credential flow for the intended provider.
|
|
|
147
147
|
Signing in again does not renew an expired API key.
|
|
148
148
|
`quota-exhausted` includes depleted credits.
|
|
149
149
|
Restore credits or quota through the intended provider before rechecking.
|
|
150
|
+
|
|
150
151
|
Ennodia reads terminal-formatted native errors and returns the matching recovery action.
|
|
152
|
+
A worker's plain-text answer does not trigger a sign-in or capacity recovery action.
|
|
151
153
|
|
|
152
154
|
Hermes uses the full `hermes chat` CLI. The legacy `hermes-agent` executable is not compatible.
|
|
153
155
|
|
package/package.json
CHANGED
package/src/core.ts
CHANGED
|
@@ -882,9 +882,9 @@ export class EnnodiaCore {
|
|
|
882
882
|
}
|
|
883
883
|
|
|
884
884
|
async startRun(input: RunStartWithSkillIdsInput): Promise<RunView> {
|
|
885
|
-
if (input.continueTaskId
|
|
885
|
+
if (input.continueTaskId) {
|
|
886
886
|
const previous = this.taskManager.get(input.continueTaskId, { includeOutput: false, includeEvents: false });
|
|
887
|
-
if (previous) input = { ...input, cwd: previous.cwd };
|
|
887
|
+
if (previous) input = { ...input, cwd: input.cwd ?? previous.cwd, model: input.model ?? previous.model };
|
|
888
888
|
}
|
|
889
889
|
const { skillIds, ...runInput } = input;
|
|
890
890
|
const skills = runInput.skills ??
|
package/src/readiness.ts
CHANGED
|
@@ -41,16 +41,20 @@ export class HarnessReadinessError extends Error {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/** Recognize native failure envelopes, never quoted prose inside an answer. */
|
|
44
|
-
export function nativeReadinessFailure(stdout: string, stderr: string): ReadinessState | undefined {
|
|
45
|
-
const
|
|
46
|
-
|
|
44
|
+
export function nativeReadinessFailure(stdout: string, stderr: string, allowPlainStdout = false): ReadinessState | undefined {
|
|
45
|
+
const stderrLines = stripVTControlCharacters(stderr).split(/\r?\n/);
|
|
46
|
+
const lines = [...stderrLines, ...stripVTControlCharacters(stdout).split(/\r?\n/)];
|
|
47
|
+
for (const [index, line] of lines.entries()) {
|
|
47
48
|
let message = line.trim();
|
|
48
49
|
try {
|
|
49
50
|
const event = JSON.parse(line);
|
|
50
51
|
if (event.type === "error") message = typeof event.message === "string" ? event.message : event.error?.message ?? "";
|
|
51
52
|
else if (event.type === "turn.failed") message = event.error?.message ?? "";
|
|
52
53
|
else continue;
|
|
53
|
-
} catch {
|
|
54
|
+
} catch {
|
|
55
|
+
// Only status/nonce checks can distinguish plain stdout from worker prose.
|
|
56
|
+
if (index >= stderrLines.length && !allowPlainStdout) continue;
|
|
57
|
+
}
|
|
54
58
|
message = stripVTControlCharacters(message).trim();
|
|
55
59
|
if (/^(?:Error:\s*)?(?:This |The |Your )?API key (?:has expired|is expired)\b/i.test(message)) return "credentials-expired";
|
|
56
60
|
if (/^(?:(?:API )?Error:\s*)?(?:Failed to authenticate\b|OAuth session expired\b|Authentication failed\b|Not logged in\b|Unauthorized\b|401\b|Re-authentication required\b|No access token found\b|Token refresh failed\b|Failed to refresh (?:OAuth|token)\b|Your authentication token .*expired\b)/i.test(message)) return "login-required";
|
|
@@ -192,7 +196,7 @@ export class HarnessReadinessManager {
|
|
|
192
196
|
const auth = recipe(h.id).auth;
|
|
193
197
|
if (auth) {
|
|
194
198
|
const result = await this.runner({ command: h.commandPath, args: auth }, 5_000);
|
|
195
|
-
const state = nativeReadinessFailure(result.stdout, result.stderr);
|
|
199
|
+
const state = nativeReadinessFailure(result.stdout, result.stderr, true);
|
|
196
200
|
if (state) return this.value(h, state, input.model);
|
|
197
201
|
if (h.id === "claude-code") {
|
|
198
202
|
try { if (JSON.parse(result.stdout).loggedIn === false) return this.value(h, "login-required", input.model); } catch { /* verification below */ }
|
|
@@ -206,7 +210,7 @@ export class HarnessReadinessManager {
|
|
|
206
210
|
try {
|
|
207
211
|
const spec = adapter.buildCommand(h.commandPath, { prompt: `Reply with exactly ${nonce}. Do not use tools, read files, or perform any other work.`, cwd: dir, model: input.model, timeoutMs: 20_000, finalMessagePath: join(dir, "answer.txt"), nativeSandbox: adapter.supportsNativeSandbox ? "read-only" : undefined });
|
|
208
212
|
const result = await this.runner(spec, 25_000);
|
|
209
|
-
const failure = nativeReadinessFailure(result.stdout, result.stderr);
|
|
213
|
+
const failure = nativeReadinessFailure(result.stdout, result.stderr, true);
|
|
210
214
|
if (failure) return this.value(h, failure, input.model);
|
|
211
215
|
if (result.timedOut || result.exitCode !== 0 || adapter.failureReason?.(result.stdout, result.stderr)) return this.value(h, "unreachable", input.model);
|
|
212
216
|
let answer = adapter.readinessAnswer ? adapter.readinessAnswer(result.stdout) ?? "" : result.stdout;
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ENNODIA_VERSION = "0.5.
|
|
1
|
+
export const ENNODIA_VERSION = "0.5.1";
|