@theokit/sdk 4.25.0 → 4.26.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.
Files changed (36) hide show
  1. package/dist/{chunk-4HKMQEPX.js → chunk-KDNBTPY2.js} +3 -3
  2. package/dist/{chunk-4HKMQEPX.js.map → chunk-KDNBTPY2.js.map} +1 -1
  3. package/dist/{chunk-F3XVLFLM.js → chunk-PSJN532Q.js} +5 -5
  4. package/dist/{chunk-F3XVLFLM.js.map → chunk-PSJN532Q.js.map} +1 -1
  5. package/dist/{chunk-7RMWOMDB.cjs → chunk-R43CNCES.cjs} +5 -5
  6. package/dist/{chunk-7RMWOMDB.cjs.map → chunk-R43CNCES.cjs.map} +1 -1
  7. package/dist/{chunk-CJ6YJ2L3.cjs → chunk-ZUBIEQJF.cjs} +7 -7
  8. package/dist/{chunk-CJ6YJ2L3.cjs.map → chunk-ZUBIEQJF.cjs.map} +1 -1
  9. package/dist/{cron-x3muPNgg.d.cts → cron-D0JKR-yX.d.cts} +2 -1
  10. package/dist/{cron-B_NkE_VM.d.ts → cron-DivRaEmN.d.ts} +2 -1
  11. package/dist/cron.cjs +3 -3
  12. package/dist/cron.d.cts +1 -1
  13. package/dist/cron.d.ts +1 -1
  14. package/dist/cron.js +2 -2
  15. package/dist/errors.d.ts +3 -424
  16. package/dist/eval.cjs +2 -2
  17. package/dist/eval.js +1 -1
  18. package/dist/index.cjs +22 -22
  19. package/dist/index.d.cts +16 -21
  20. package/dist/index.d.ts +16 -21
  21. package/dist/index.js +5 -5
  22. package/dist/internal/judge/judge-call.d.ts +32 -19
  23. package/dist/{judge-call-VIMNK5TA.js → judge-call-CEQ3FYYD.js} +38 -4
  24. package/dist/judge-call-CEQ3FYYD.js.map +1 -0
  25. package/dist/{judge-call-7CF7D334.cjs → judge-call-QG4WZ7F3.cjs} +38 -3
  26. package/dist/judge-call-QG4WZ7F3.cjs.map +1 -0
  27. package/dist/{run-until-DB3LVGZS.cjs → run-until-PNO3QQLI.cjs} +11 -2
  28. package/dist/run-until-PNO3QQLI.cjs.map +1 -0
  29. package/dist/{run-until-2PX4QBHZ.js → run-until-XLHEHRQM.js} +11 -2
  30. package/dist/run-until-XLHEHRQM.js.map +1 -0
  31. package/dist/types/goal-events.d.ts +2 -1
  32. package/package.json +1 -1
  33. package/dist/judge-call-7CF7D334.cjs.map +0 -1
  34. package/dist/judge-call-VIMNK5TA.js.map +0 -1
  35. package/dist/run-until-2PX4QBHZ.js.map +0 -1
  36. package/dist/run-until-DB3LVGZS.cjs.map +0 -1
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { T as TheokitAgentError, B as BudgetOptions, a as BudgetHandle, b as BudgetSnapshot, E as ErrorMetadata } from './errors-BdL-buYn.cjs';
2
2
  export { A as AgentDisposedError, c as AgentRunError, d as AgentRunErrorCode, e as AuthenticationError, f as BudgetExceedEvent, g as BudgetExceededError, h as BudgetLimit, i as BudgetMode, j as BudgetScope, k as BudgetThresholdEvent, l as BudgetWindow, C as ConfigurationError, m as ErrorCode, I as IntegrationNotConnectedError, n as InvalidTaskIdError, M as MemoryAdapterError, o as MemoryAdapterErrorCode, N as NetworkError, R as RateLimitError, p as TaskNotFoundError, U as UnknownAgentError, q as UnsupportedBudgetOperationError, r as UnsupportedRunOperationError, s as UnsupportedTaskOperationError, t as isTransientError } from './errors-BdL-buYn.cjs';
3
- import { A as AgentOptions, L as LocalOptions, P as ProviderRoutingSettings, S as SystemPromptResolver, C as CloudOptions, M as MemorySettings, a as AgentDefinition, b as ContextSettings, c as PluginsSettings, d as SkillsSettings, e as SDKAgent, f as ListAgentsOptions, g as ListResult, h as SDKAgentInfo, G as GetAgentOptions, i as ListRunsOptions, j as GetRunOptions, k as AgentOperationOptions, l as Plugin$1, m as ProviderProfile, I as InlineSkill, n as GoalOptions, o as GoalEvent, p as GoalResult, B as BudgetTracker, q as MemoryProvider, r as MemoryId, s as PreToolCallDecision, t as StepResult, u as SDKProvider } from './cron-x3muPNgg.cjs';
4
- export { v as ActiveMemoryPassArgs, w as ActiveMemoryPassResult, x as AgentMemory, y as BudgetCheck, z as BudgetTotal, D as BudgetUsageEvent, E as CloudEnv, F as CloudRepo, H as ContextBudget, J as ContextManagerKind, K as ContextSnapshot, N as ContextSource, O as ContextSourceStatus, Q as CreateSkillSpec, R as Cron, T as CronCreateOptions, U as CronGetOptions, V as CronJob, W as CronJobStatus, X as CronListOptions, Y as CronOperationOptions, Z as CronRunOptions, _ as CronRuntime, $ as CronSchedulerStatus, a0 as CronStartOptions, a1 as HookName, a2 as InvalidateCacheOptions, a3 as MemoryAdapter, a4 as MemoryAdapterCapabilities, a5 as MemoryContext, a6 as MemoryFact, a7 as MemoryProviderHandle, a8 as MemoryProviderInitOptions, a9 as MemoryRevision, aa as MemoryToolSchema, ab as MemoryTurnMessage, ac as PersonalityPreset, ad as PluginContext, ae as PostAssistantReplyContext, af as PreToolCallContext, ag as PreUserSendContext, ah as PreUserSendResult, ai as ProviderCapability, aj as ProviderRoute, ak as ProviderTransform, al as ProviderTransformContext, am as RecordSessionSummaryArgs, an as ResolvedProviderRoute, ao as RunUntilIterator, ap as SDKAgentPlugins, aq as SDKAgentSkillDetail, ar as SDKAgentSkills, as as SDKArtifact, at as SDKContextManager, au as SDKPluginMetadata, av as SDKProvidersManager, aw as SessionRecord, ax as SessionStore, ay as SettingSource, az as Skill, aA as SkillsResolver, aB as SkillsResolverContext, aC as SystemPromptContext, aD as SystemPromptMemoryFact, aE as SystemPromptSkillRef, aF as TelemetrySettings } from './cron-x3muPNgg.cjs';
3
+ import { A as AgentOptions, L as LocalOptions, P as ProviderRoutingSettings, S as SystemPromptResolver, C as CloudOptions, M as MemorySettings, a as AgentDefinition, b as ContextSettings, c as PluginsSettings, d as SkillsSettings, e as SDKAgent, f as ListAgentsOptions, g as ListResult, h as SDKAgentInfo, G as GetAgentOptions, i as ListRunsOptions, j as GetRunOptions, k as AgentOperationOptions, l as Plugin$1, m as ProviderProfile, I as InlineSkill, n as GoalOptions, o as GoalEvent, p as GoalResult, B as BudgetTracker, q as MemoryProvider, r as MemoryId, s as PreToolCallDecision, t as StepResult, u as SDKProvider } from './cron-D0JKR-yX.cjs';
4
+ export { v as ActiveMemoryPassArgs, w as ActiveMemoryPassResult, x as AgentMemory, y as BudgetCheck, z as BudgetTotal, D as BudgetUsageEvent, E as CloudEnv, F as CloudRepo, H as ContextBudget, J as ContextManagerKind, K as ContextSnapshot, N as ContextSource, O as ContextSourceStatus, Q as CreateSkillSpec, R as Cron, T as CronCreateOptions, U as CronGetOptions, V as CronJob, W as CronJobStatus, X as CronListOptions, Y as CronOperationOptions, Z as CronRunOptions, _ as CronRuntime, $ as CronSchedulerStatus, a0 as CronStartOptions, a1 as HookName, a2 as InvalidateCacheOptions, a3 as MemoryAdapter, a4 as MemoryAdapterCapabilities, a5 as MemoryContext, a6 as MemoryFact, a7 as MemoryProviderHandle, a8 as MemoryProviderInitOptions, a9 as MemoryRevision, aa as MemoryToolSchema, ab as MemoryTurnMessage, ac as PersonalityPreset, ad as PluginContext, ae as PostAssistantReplyContext, af as PreToolCallContext, ag as PreUserSendContext, ah as PreUserSendResult, ai as ProviderCapability, aj as ProviderRoute, ak as ProviderTransform, al as ProviderTransformContext, am as RecordSessionSummaryArgs, an as ResolvedProviderRoute, ao as RunUntilIterator, ap as SDKAgentPlugins, aq as SDKAgentSkillDetail, ar as SDKAgentSkills, as as SDKArtifact, at as SDKContextManager, au as SDKPluginMetadata, av as SDKProvidersManager, aw as SessionRecord, ax as SessionStore, ay as SettingSource, az as Skill, aA as SkillsResolver, aB as SkillsResolverContext, aC as SystemPromptContext, aD as SystemPromptMemoryFact, aE as SystemPromptSkillRef, aF as TelemetrySettings } from './cron-D0JKR-yX.cjs';
5
5
  import { R as RunResult, M as ModelSelection, C as CustomTool, a as McpServerConfig, b as Run, P as Processor, T as ToolResultContentBlock, c as PermissionMode, d as PermissionEngine, e as RunEventSink, S as SDKMessage } from './run-OJbGyweZ.cjs';
6
6
  export { A as AgentConversationTurn, f as AssistantMessage, g as CompletionCheck, h as CompletionCheckResult, i as ConversationStep, j as ConversationTurn, k as CostBreakdown, l as CostSource, m as CostStatus, D as DoomLoopThresholds, G as GenerateOptions, n as GenerateRunResult, I as ImageBlock, o as InputProcessorContext, p as InteractionUpdate, q as McpAuthConfig, r as McpHttpServerConfig, s as McpOAuthConfig, t as McpStdioServerConfig, u as MessageOrigin, v as ModelParameterValue, O as OutputProcessorContext, w as PartialToolCallUpdate, x as PermissionAction, y as PermissionEngineOptions, z as PermissionRule, B as ProcessorControls, E as ProcessorTripwire, F as ProcessorViolation, H as RunCompactBoundaryEvent, J as RunCompletionCheckEvent, K as RunErrorDetail, L as RunEvent, N as RunGitInfo, Q as RunOperation, U as RunPermissionDeniedEvent, V as RunRateLimitEvent, W as RunStatus, X as RunTaskCompletedEvent, Y as RunTaskStartedEvent, Z as RunTaskUpdatedEvent, _ as RunToCompletionOptions, $ as RunToCompletionResult, a0 as RunToolProgressEvent, a1 as RunTripwireEvent, a2 as SDKAssistantMessage, a3 as SDKImage, a4 as SDKImageDimension, a5 as SDKObjectDelta, a6 as SDKRequestMessage, a7 as SDKStatusMessage, a8 as SDKSystemMessage, a9 as SDKTaskMessage, aa as SDKThinkingMessage, ab as SDKToolUseMessage, ac as SDKUserMessage, ad as SDKUserMessageEvent, ae as SendOptions, af as ShellCommand, ag as ShellConversationTurn, ah as ShellOutput, ai as ShellOutputDeltaUpdate, aj as StepCompletedUpdate, ak as StepStartedUpdate, al as StreamToCompletionResult, am as SummaryCompletedUpdate, an as SummaryStartedUpdate, ao as SummaryUpdate, ap as TextBlock, aq as TextDeltaUpdate, ar as ThinkingCompletedUpdate, as as ThinkingDeltaUpdate, at as ThinkingMessage, au as TokenDeltaUpdate, av as TokenUsage, aw as ToolCall, ax as ToolCallCompletedUpdate, ay as ToolCallStartedUpdate, az as ToolContextMessage, aA as ToolResult, aB as ToolResultGuardOptions, aC as ToolUseBlock, aD as TurnEndedUpdate, aE as UserMessage, aF as UserMessageAppendedUpdate, aG as applyMode, aH as emitRunEvent } from './run-OJbGyweZ.cjs';
7
7
  import * as zod from 'zod';
@@ -1163,24 +1163,6 @@ declare class EventBus<Events extends Record<string, unknown>> {
1163
1163
  once<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): () => void;
1164
1164
  }
1165
1165
 
1166
- /**
1167
- * Judge call primitive (T2.2, ADRs D119-D121).
1168
- *
1169
- * Instantiates a short-lived auxiliary agent that evaluates whether a
1170
- * goal is satisfied. The auxiliary judge runs with `tools: []` and a
1171
- * cheap model (default `openai/gpt-4o-mini`) — see ADR D119. The judge
1172
- * model needs only API access; we read `OPENROUTER_API_KEY` directly
1173
- * from the environment (EC-A — single source of truth) and let the
1174
- * caller override via {@link JudgeOptions.apiKey} for Anthropic or
1175
- * direct-OpenAI environments.
1176
- *
1177
- * NOTE: judge aux agents created from inside a `forkAgent` context will
1178
- * inherit the parent fork's whitelist via AsyncLocalStorage (EC-J).
1179
- * `tools: []` keeps this benign today; future callers that add tools to
1180
- * a judge should be aware.
1181
- *
1182
- * @internal
1183
- */
1184
1166
  /** Inputs to the judge — pure data. */
1185
1167
  interface JudgeContext {
1186
1168
  goal: string;
@@ -1189,8 +1171,21 @@ interface JudgeContext {
1189
1171
  }
1190
1172
  /** Caller-supplied tuning knobs for the judge call. */
1191
1173
  interface JudgeOptions {
1192
- /** Judge model identifier. Default `"openai/gpt-4o-mini"` (ADR D119). */
1174
+ /**
1175
+ * Judge model identifier. Quando ausente, DERIVA de {@link agentModel} — e só cai no literal
1176
+ * `"openai/gpt-4o-mini"` se nem esse for informado.
1177
+ *
1178
+ * M80 — o default fixo era provider-cego: ele só resolve em OpenRouter. Com chave Anthropic dá
1179
+ * 404, com bearer OAuth dá 401, e em ambos o goal queimava 3 turnos inteiros antes de falhar com
1180
+ * razão enganosa. O agent-builder já contornava isso derivando por conta própria; o conhecimento
1181
+ * pertence aqui.
1182
+ */
1193
1183
  judgeModel?: string;
1184
+ /**
1185
+ * M80 — o modelo do agente CONDUZIDO. É a base da derivação: um judge que roda no mesmo modelo do
1186
+ * chat funciona onde o chat funciona.
1187
+ */
1188
+ agentModel?: string;
1194
1189
  /** Override env. Default `process.env.OPENROUTER_API_KEY` (EC-A). */
1195
1190
  apiKey?: string;
1196
1191
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { T as TheokitAgentError, B as BudgetOptions, a as BudgetHandle, b as BudgetSnapshot, E as ErrorMetadata } from './errors-DHZtSNnj.js';
2
2
  export { A as AgentDisposedError, c as AgentRunError, d as AgentRunErrorCode, e as AuthenticationError, f as BudgetExceedEvent, g as BudgetExceededError, h as BudgetLimit, i as BudgetMode, j as BudgetScope, k as BudgetThresholdEvent, l as BudgetWindow, C as ConfigurationError, m as ErrorCode, I as IntegrationNotConnectedError, n as InvalidTaskIdError, M as MemoryAdapterError, o as MemoryAdapterErrorCode, N as NetworkError, R as RateLimitError, p as TaskNotFoundError, U as UnknownAgentError, q as UnsupportedBudgetOperationError, r as UnsupportedRunOperationError, s as UnsupportedTaskOperationError, t as isTransientError } from './errors-DHZtSNnj.js';
3
- import { A as AgentOptions, L as LocalOptions, P as ProviderRoutingSettings, S as SystemPromptResolver, C as CloudOptions, M as MemorySettings, a as AgentDefinition, b as ContextSettings, c as PluginsSettings, d as SkillsSettings, e as SDKAgent, f as ListAgentsOptions, g as ListResult, h as SDKAgentInfo, G as GetAgentOptions, i as ListRunsOptions, j as GetRunOptions, k as AgentOperationOptions, l as Plugin$1, m as ProviderProfile, I as InlineSkill, n as GoalOptions, o as GoalEvent, p as GoalResult, B as BudgetTracker, q as MemoryProvider, r as MemoryId, s as PreToolCallDecision, t as StepResult, u as SDKProvider } from './cron-B_NkE_VM.js';
4
- export { v as ActiveMemoryPassArgs, w as ActiveMemoryPassResult, x as AgentMemory, y as BudgetCheck, z as BudgetTotal, D as BudgetUsageEvent, E as CloudEnv, F as CloudRepo, H as ContextBudget, J as ContextManagerKind, K as ContextSnapshot, N as ContextSource, O as ContextSourceStatus, Q as CreateSkillSpec, R as Cron, T as CronCreateOptions, U as CronGetOptions, V as CronJob, W as CronJobStatus, X as CronListOptions, Y as CronOperationOptions, Z as CronRunOptions, _ as CronRuntime, $ as CronSchedulerStatus, a0 as CronStartOptions, a1 as HookName, a2 as InvalidateCacheOptions, a3 as MemoryAdapter, a4 as MemoryAdapterCapabilities, a5 as MemoryContext, a6 as MemoryFact, a7 as MemoryProviderHandle, a8 as MemoryProviderInitOptions, a9 as MemoryRevision, aa as MemoryToolSchema, ab as MemoryTurnMessage, ac as PersonalityPreset, ad as PluginContext, ae as PostAssistantReplyContext, af as PreToolCallContext, ag as PreUserSendContext, ah as PreUserSendResult, ai as ProviderCapability, aj as ProviderRoute, ak as ProviderTransform, al as ProviderTransformContext, am as RecordSessionSummaryArgs, an as ResolvedProviderRoute, ao as RunUntilIterator, ap as SDKAgentPlugins, aq as SDKAgentSkillDetail, ar as SDKAgentSkills, as as SDKArtifact, at as SDKContextManager, au as SDKPluginMetadata, av as SDKProvidersManager, aw as SessionRecord, ax as SessionStore, ay as SettingSource, az as Skill, aA as SkillsResolver, aB as SkillsResolverContext, aC as SystemPromptContext, aD as SystemPromptMemoryFact, aE as SystemPromptSkillRef, aF as TelemetrySettings } from './cron-B_NkE_VM.js';
3
+ import { A as AgentOptions, L as LocalOptions, P as ProviderRoutingSettings, S as SystemPromptResolver, C as CloudOptions, M as MemorySettings, a as AgentDefinition, b as ContextSettings, c as PluginsSettings, d as SkillsSettings, e as SDKAgent, f as ListAgentsOptions, g as ListResult, h as SDKAgentInfo, G as GetAgentOptions, i as ListRunsOptions, j as GetRunOptions, k as AgentOperationOptions, l as Plugin$1, m as ProviderProfile, I as InlineSkill, n as GoalOptions, o as GoalEvent, p as GoalResult, B as BudgetTracker, q as MemoryProvider, r as MemoryId, s as PreToolCallDecision, t as StepResult, u as SDKProvider } from './cron-DivRaEmN.js';
4
+ export { v as ActiveMemoryPassArgs, w as ActiveMemoryPassResult, x as AgentMemory, y as BudgetCheck, z as BudgetTotal, D as BudgetUsageEvent, E as CloudEnv, F as CloudRepo, H as ContextBudget, J as ContextManagerKind, K as ContextSnapshot, N as ContextSource, O as ContextSourceStatus, Q as CreateSkillSpec, R as Cron, T as CronCreateOptions, U as CronGetOptions, V as CronJob, W as CronJobStatus, X as CronListOptions, Y as CronOperationOptions, Z as CronRunOptions, _ as CronRuntime, $ as CronSchedulerStatus, a0 as CronStartOptions, a1 as HookName, a2 as InvalidateCacheOptions, a3 as MemoryAdapter, a4 as MemoryAdapterCapabilities, a5 as MemoryContext, a6 as MemoryFact, a7 as MemoryProviderHandle, a8 as MemoryProviderInitOptions, a9 as MemoryRevision, aa as MemoryToolSchema, ab as MemoryTurnMessage, ac as PersonalityPreset, ad as PluginContext, ae as PostAssistantReplyContext, af as PreToolCallContext, ag as PreUserSendContext, ah as PreUserSendResult, ai as ProviderCapability, aj as ProviderRoute, ak as ProviderTransform, al as ProviderTransformContext, am as RecordSessionSummaryArgs, an as ResolvedProviderRoute, ao as RunUntilIterator, ap as SDKAgentPlugins, aq as SDKAgentSkillDetail, ar as SDKAgentSkills, as as SDKArtifact, at as SDKContextManager, au as SDKPluginMetadata, av as SDKProvidersManager, aw as SessionRecord, ax as SessionStore, ay as SettingSource, az as Skill, aA as SkillsResolver, aB as SkillsResolverContext, aC as SystemPromptContext, aD as SystemPromptMemoryFact, aE as SystemPromptSkillRef, aF as TelemetrySettings } from './cron-DivRaEmN.js';
5
5
  import { R as RunResult, M as ModelSelection, C as CustomTool, a as McpServerConfig, b as Run, P as Processor, T as ToolResultContentBlock, c as PermissionMode, d as PermissionEngine, e as RunEventSink, S as SDKMessage } from './run-OJbGyweZ.js';
6
6
  export { A as AgentConversationTurn, f as AssistantMessage, g as CompletionCheck, h as CompletionCheckResult, i as ConversationStep, j as ConversationTurn, k as CostBreakdown, l as CostSource, m as CostStatus, D as DoomLoopThresholds, G as GenerateOptions, n as GenerateRunResult, I as ImageBlock, o as InputProcessorContext, p as InteractionUpdate, q as McpAuthConfig, r as McpHttpServerConfig, s as McpOAuthConfig, t as McpStdioServerConfig, u as MessageOrigin, v as ModelParameterValue, O as OutputProcessorContext, w as PartialToolCallUpdate, x as PermissionAction, y as PermissionEngineOptions, z as PermissionRule, B as ProcessorControls, E as ProcessorTripwire, F as ProcessorViolation, H as RunCompactBoundaryEvent, J as RunCompletionCheckEvent, K as RunErrorDetail, L as RunEvent, N as RunGitInfo, Q as RunOperation, U as RunPermissionDeniedEvent, V as RunRateLimitEvent, W as RunStatus, X as RunTaskCompletedEvent, Y as RunTaskStartedEvent, Z as RunTaskUpdatedEvent, _ as RunToCompletionOptions, $ as RunToCompletionResult, a0 as RunToolProgressEvent, a1 as RunTripwireEvent, a2 as SDKAssistantMessage, a3 as SDKImage, a4 as SDKImageDimension, a5 as SDKObjectDelta, a6 as SDKRequestMessage, a7 as SDKStatusMessage, a8 as SDKSystemMessage, a9 as SDKTaskMessage, aa as SDKThinkingMessage, ab as SDKToolUseMessage, ac as SDKUserMessage, ad as SDKUserMessageEvent, ae as SendOptions, af as ShellCommand, ag as ShellConversationTurn, ah as ShellOutput, ai as ShellOutputDeltaUpdate, aj as StepCompletedUpdate, ak as StepStartedUpdate, al as StreamToCompletionResult, am as SummaryCompletedUpdate, an as SummaryStartedUpdate, ao as SummaryUpdate, ap as TextBlock, aq as TextDeltaUpdate, ar as ThinkingCompletedUpdate, as as ThinkingDeltaUpdate, at as ThinkingMessage, au as TokenDeltaUpdate, av as TokenUsage, aw as ToolCall, ax as ToolCallCompletedUpdate, ay as ToolCallStartedUpdate, az as ToolContextMessage, aA as ToolResult, aB as ToolResultGuardOptions, aC as ToolUseBlock, aD as TurnEndedUpdate, aE as UserMessage, aF as UserMessageAppendedUpdate, aG as applyMode, aH as emitRunEvent } from './run-OJbGyweZ.js';
7
7
  import * as zod from 'zod';
@@ -1163,24 +1163,6 @@ declare class EventBus<Events extends Record<string, unknown>> {
1163
1163
  once<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): () => void;
1164
1164
  }
1165
1165
 
1166
- /**
1167
- * Judge call primitive (T2.2, ADRs D119-D121).
1168
- *
1169
- * Instantiates a short-lived auxiliary agent that evaluates whether a
1170
- * goal is satisfied. The auxiliary judge runs with `tools: []` and a
1171
- * cheap model (default `openai/gpt-4o-mini`) — see ADR D119. The judge
1172
- * model needs only API access; we read `OPENROUTER_API_KEY` directly
1173
- * from the environment (EC-A — single source of truth) and let the
1174
- * caller override via {@link JudgeOptions.apiKey} for Anthropic or
1175
- * direct-OpenAI environments.
1176
- *
1177
- * NOTE: judge aux agents created from inside a `forkAgent` context will
1178
- * inherit the parent fork's whitelist via AsyncLocalStorage (EC-J).
1179
- * `tools: []` keeps this benign today; future callers that add tools to
1180
- * a judge should be aware.
1181
- *
1182
- * @internal
1183
- */
1184
1166
  /** Inputs to the judge — pure data. */
1185
1167
  interface JudgeContext {
1186
1168
  goal: string;
@@ -1189,8 +1171,21 @@ interface JudgeContext {
1189
1171
  }
1190
1172
  /** Caller-supplied tuning knobs for the judge call. */
1191
1173
  interface JudgeOptions {
1192
- /** Judge model identifier. Default `"openai/gpt-4o-mini"` (ADR D119). */
1174
+ /**
1175
+ * Judge model identifier. Quando ausente, DERIVA de {@link agentModel} — e só cai no literal
1176
+ * `"openai/gpt-4o-mini"` se nem esse for informado.
1177
+ *
1178
+ * M80 — o default fixo era provider-cego: ele só resolve em OpenRouter. Com chave Anthropic dá
1179
+ * 404, com bearer OAuth dá 401, e em ambos o goal queimava 3 turnos inteiros antes de falhar com
1180
+ * razão enganosa. O agent-builder já contornava isso derivando por conta própria; o conhecimento
1181
+ * pertence aqui.
1182
+ */
1193
1183
  judgeModel?: string;
1184
+ /**
1185
+ * M80 — o modelo do agente CONDUZIDO. É a base da derivação: um judge que roda no mesmo modelo do
1186
+ * chat funciona onde o chat funciona.
1187
+ */
1188
+ agentModel?: string;
1194
1189
  /** Override env. Default `process.env.OPENROUTER_API_KEY` (EC-A). */
1195
1190
  apiKey?: string;
1196
1191
  }
package/dist/index.js CHANGED
@@ -5,9 +5,9 @@ import './chunk-GJAGKFTR.js';
5
5
  import { Workflow, agentStep } from './chunk-BFWPZMG7.js';
6
6
  import './chunk-UVNG67DG.js';
7
7
  import './chunk-CAH3G4IS.js';
8
- export { Cron } from './chunk-4HKMQEPX.js';
9
- import { MEMORY_EMBEDDING_ADAPTERS, resolveApiKey, shouldUseFixtureMode, isFixtureApiKey, httpRequest, DEFAULT_AGENTIC_MODEL_ID, Agent } from './chunk-F3XVLFLM.js';
10
- export { Agent, AgentBuilder, Tool, ToolError, UsageAccumulator, computeCost, getPricingEntry } from './chunk-F3XVLFLM.js';
8
+ export { Cron } from './chunk-KDNBTPY2.js';
9
+ import { MEMORY_EMBEDDING_ADAPTERS, resolveApiKey, shouldUseFixtureMode, isFixtureApiKey, httpRequest, DEFAULT_AGENTIC_MODEL_ID, Agent } from './chunk-PSJN532Q.js';
10
+ export { Agent, AgentBuilder, Tool, ToolError, UsageAccumulator, computeCost, getPricingEntry } from './chunk-PSJN532Q.js';
11
11
  import { configure, submit, list, get, cancel, subscribe } from './chunk-HRA3CPGG.js';
12
12
  export { emitRunEvent } from './chunk-HRA3CPGG.js';
13
13
  import './chunk-SQLZ7ONU.js';
@@ -694,9 +694,9 @@ var EventBus = class {
694
694
  // src/goal-loop.ts
695
695
  function runGoalLoop(agent, goal, options, depsOverride) {
696
696
  async function* wrap() {
697
- const { runUntilImpl } = await import('./run-until-2PX4QBHZ.js');
697
+ const { runUntilImpl } = await import('./run-until-XLHEHRQM.js');
698
698
  const deps = depsOverride ?? await (async () => {
699
- const { judgeCallImpl } = await import('./judge-call-VIMNK5TA.js');
699
+ const { judgeCallImpl } = await import('./judge-call-CEQ3FYYD.js');
700
700
  const { getAgentFacade } = await import('./agent-factory-registry-ZVTABLEY.js');
701
701
  const create = getAgentFacade().create;
702
702
  return {
@@ -1,21 +1,4 @@
1
- /**
2
- * Judge call primitive (T2.2, ADRs D119-D121).
3
- *
4
- * Instantiates a short-lived auxiliary agent that evaluates whether a
5
- * goal is satisfied. The auxiliary judge runs with `tools: []` and a
6
- * cheap model (default `openai/gpt-4o-mini`) — see ADR D119. The judge
7
- * model needs only API access; we read `OPENROUTER_API_KEY` directly
8
- * from the environment (EC-A — single source of truth) and let the
9
- * caller override via {@link JudgeOptions.apiKey} for Anthropic or
10
- * direct-OpenAI environments.
11
- *
12
- * NOTE: judge aux agents created from inside a `forkAgent` context will
13
- * inherit the parent fork's whitelist via AsyncLocalStorage (EC-J).
14
- * `tools: []` keeps this benign today; future callers that add tools to
15
- * a judge should be aware.
16
- *
17
- * @internal
18
- */
1
+ import { TheokitAgentError } from "../../errors.js";
19
2
  /** Inputs to the judge — pure data. */
20
3
  export interface JudgeContext {
21
4
  goal: string;
@@ -24,11 +7,41 @@ export interface JudgeContext {
24
7
  }
25
8
  /** Caller-supplied tuning knobs for the judge call. */
26
9
  export interface JudgeOptions {
27
- /** Judge model identifier. Default `"openai/gpt-4o-mini"` (ADR D119). */
10
+ /**
11
+ * Judge model identifier. Quando ausente, DERIVA de {@link agentModel} — e só cai no literal
12
+ * `"openai/gpt-4o-mini"` se nem esse for informado.
13
+ *
14
+ * M80 — o default fixo era provider-cego: ele só resolve em OpenRouter. Com chave Anthropic dá
15
+ * 404, com bearer OAuth dá 401, e em ambos o goal queimava 3 turnos inteiros antes de falhar com
16
+ * razão enganosa. O agent-builder já contornava isso derivando por conta própria; o conhecimento
17
+ * pertence aqui.
18
+ */
28
19
  judgeModel?: string;
20
+ /**
21
+ * M80 — o modelo do agente CONDUZIDO. É a base da derivação: um judge que roda no mesmo modelo do
22
+ * chat funciona onde o chat funciona.
23
+ */
24
+ agentModel?: string;
29
25
  /** Override env. Default `process.env.OPENROUTER_API_KEY` (EC-A). */
30
26
  apiKey?: string;
31
27
  }
28
+ /**
29
+ * M80 — a credencial ou o modelo do judge não servem: 401/404.
30
+ *
31
+ * Falha RÁPIDA por design. `rules/error-handling.md § 2` separa recuperável de irrecuperável, e um
32
+ * modelo inexistente não passa a existir no retry — dobrar isso em `{parseFailed: true}` fazia o loop
33
+ * tentar três vezes e reportar "failed" por limite de falhas consecutivas, escondendo que a causa era
34
+ * credencial. Falha lenta e opaca trocada por rápida e clara.
35
+ *
36
+ * Falha de PARSE e erro de rede continuam dobrados: são recuperáveis, e o loop já decide por falhas
37
+ * consecutivas.
38
+ */
39
+ export declare class JudgeCredentialError extends TheokitAgentError {
40
+ readonly httpStatus: number;
41
+ readonly judgeModel: string;
42
+ readonly name = "JudgeCredentialError";
43
+ constructor(httpStatus: number, judgeModel: string, cause: unknown);
44
+ }
32
45
  /** Dependencies injected so `judge-call.ts` stays free of `Agent` import. */
33
46
  export interface JudgeDeps {
34
47
  create: (options: AgentOptions) => Promise<SDKAgent>;
@@ -1,7 +1,11 @@
1
+ import { TheokitAgentError } from './chunk-WLKFWQSJ.js';
2
+ import './chunk-JTFYYKDT.js';
3
+
1
4
  // src/internal/judge/parse-verdict.ts
2
5
  var DONE_PREFIX = "DONE:";
3
6
  var CONTINUE_PREFIX = "CONTINUE:";
4
7
  var SKIPPED_PREFIX = "SKIPPED:";
8
+ var BLOCKED_PREFIX = "BLOCKED:";
5
9
  function parseVerdict(text) {
6
10
  const trimmed = text.trim();
7
11
  if (trimmed.startsWith(DONE_PREFIX)) {
@@ -18,6 +22,13 @@ function parseVerdict(text) {
18
22
  parseFailed: false
19
23
  };
20
24
  }
25
+ if (trimmed.startsWith(BLOCKED_PREFIX)) {
26
+ return {
27
+ verdict: "blocked",
28
+ reason: trimmed.slice(BLOCKED_PREFIX.length).trim(),
29
+ parseFailed: false
30
+ };
31
+ }
21
32
  if (trimmed.startsWith(SKIPPED_PREFIX)) {
22
33
  return {
23
34
  verdict: "skipped",
@@ -33,6 +44,25 @@ function parseVerdict(text) {
33
44
  }
34
45
 
35
46
  // src/internal/judge/judge-call.ts
47
+ var JudgeCredentialError = class extends TheokitAgentError {
48
+ constructor(httpStatus, judgeModel, cause) {
49
+ super(
50
+ `judge unavailable: model "${judgeModel}" returned ${String(httpStatus)}. Pass \`judgeModel\`/\`apiKey\` that resolve for this provider, or omit \`judgeModel\` to derive it from the agent being driven.`,
51
+ { code: "judge_credential", cause, isRetryable: false }
52
+ );
53
+ this.httpStatus = httpStatus;
54
+ this.judgeModel = judgeModel;
55
+ }
56
+ httpStatus;
57
+ judgeModel;
58
+ name = "JudgeCredentialError";
59
+ };
60
+ function statusHttpDe(err) {
61
+ const s = err.status ?? err.statusCode;
62
+ if (typeof s === "number") return s;
63
+ const m = /\b(401|403|404)\b/.exec(err instanceof Error ? err.message : String(err));
64
+ return m?.[1] !== void 0 ? Number(m[1]) : void 0;
65
+ }
36
66
  async function judgeCallImpl(ctx, options, deps) {
37
67
  const prompt = composeJudgePrompt(ctx);
38
68
  const apiKey = options?.apiKey ?? process.env.OPENROUTER_API_KEY;
@@ -43,7 +73,7 @@ async function judgeCallImpl(ctx, options, deps) {
43
73
  parseFailed: true
44
74
  };
45
75
  }
46
- const judgeModel = options?.judgeModel ?? "openai/gpt-4o-mini";
76
+ const judgeModel = options?.judgeModel ?? options?.agentModel ?? "openai/gpt-4o-mini";
47
77
  let auxAgent;
48
78
  try {
49
79
  auxAgent = await deps.create({
@@ -57,6 +87,10 @@ async function judgeCallImpl(ctx, options, deps) {
57
87
  const result = await run.wait();
58
88
  return parseVerdict(result.result ?? "");
59
89
  } catch (err) {
90
+ const status = statusHttpDe(err);
91
+ if (status === 401 || status === 403 || status === 404) {
92
+ throw new JudgeCredentialError(status, judgeModel, err);
93
+ }
60
94
  return {
61
95
  verdict: "continue",
62
96
  reason: `judge call failed: ${err instanceof Error ? err.message : String(err)}`,
@@ -87,6 +121,6 @@ Respond with EXACTLY one of:
87
121
  Be strict. If unclear, prefer CONTINUE.`;
88
122
  }
89
123
 
90
- export { composeJudgePrompt, judgeCallImpl };
91
- //# sourceMappingURL=judge-call-VIMNK5TA.js.map
92
- //# sourceMappingURL=judge-call-VIMNK5TA.js.map
124
+ export { JudgeCredentialError, composeJudgePrompt, judgeCallImpl };
125
+ //# sourceMappingURL=judge-call-CEQ3FYYD.js.map
126
+ //# sourceMappingURL=judge-call-CEQ3FYYD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/judge/parse-verdict.ts","../src/internal/judge/judge-call.ts"],"names":[],"mappings":"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","file":"judge-call-CEQ3FYYD.js","sourcesContent":["/**\n * Pure verdict parser (T2.1, ADRs D120-D121).\n *\n * Strict prefix matching against `DONE:`, `CONTINUE:`, `SKIPPED:`. Reason\n * is the suffix, trimmed. Anything else is fail-safe: verdict = `continue`,\n * `parseFailed: true` — caller's max-consecutive-failure cap stops the\n * loop after N flakes.\n *\n * @internal\n */\n\nimport type { JudgeResult } from \"./types.js\";\n\nconst DONE_PREFIX = \"DONE:\";\nconst CONTINUE_PREFIX = \"CONTINUE:\";\nconst SKIPPED_PREFIX = \"SKIPPED:\";\n/** M80 — o judge agora pode declarar impossibilidade, não só \"continue\". */\nconst BLOCKED_PREFIX = \"BLOCKED:\";\n\nexport function parseVerdict(text: string): JudgeResult {\n const trimmed = text.trim();\n\n if (trimmed.startsWith(DONE_PREFIX)) {\n return {\n verdict: \"done\",\n reason: trimmed.slice(DONE_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(CONTINUE_PREFIX)) {\n return {\n verdict: \"continue\",\n reason: trimmed.slice(CONTINUE_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(BLOCKED_PREFIX)) {\n return {\n verdict: \"blocked\",\n reason: trimmed.slice(BLOCKED_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(SKIPPED_PREFIX)) {\n return {\n verdict: \"skipped\",\n reason: trimmed.slice(SKIPPED_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n\n // Fail-safe: ADR D121 — prefer \"continue\" so we don't stop prematurely.\n // The runUntil loop counts consecutive parseFailed responses and bails\n // after `maxConsecutiveJudgeFailures` (default 3).\n return {\n verdict: \"continue\",\n reason: `judge response malformed: \"${trimmed.slice(0, 100)}\"`,\n parseFailed: true,\n };\n}\n","import { TheokitAgentError } from \"../../errors.js\";\n/**\n * Judge call primitive (T2.2, ADRs D119-D121).\n *\n * Instantiates a short-lived auxiliary agent that evaluates whether a\n * goal is satisfied. The auxiliary judge runs with `tools: []` and a\n * cheap model (default `openai/gpt-4o-mini`) — see ADR D119. The judge\n * model needs only API access; we read `OPENROUTER_API_KEY` directly\n * from the environment (EC-A — single source of truth) and let the\n * caller override via {@link JudgeOptions.apiKey} for Anthropic or\n * direct-OpenAI environments.\n *\n * NOTE: judge aux agents created from inside a `forkAgent` context will\n * inherit the parent fork's whitelist via AsyncLocalStorage (EC-J).\n * `tools: []` keeps this benign today; future callers that add tools to\n * a judge should be aware.\n *\n * @internal\n */\n\nimport type { AgentOptions, SDKAgent } from \"../../types/agent.js\";\nimport { parseVerdict } from \"./parse-verdict.js\";\nimport type { JudgeResult } from \"./types.js\";\n\n/** Inputs to the judge — pure data. */\nexport interface JudgeContext {\n goal: string;\n lastResponse: string;\n subgoals?: string[];\n}\n\n/** Caller-supplied tuning knobs for the judge call. */\nexport interface JudgeOptions {\n /**\n * Judge model identifier. Quando ausente, DERIVA de {@link agentModel} — e só cai no literal\n * `\"openai/gpt-4o-mini\"` se nem esse for informado.\n *\n * M80 — o default fixo era provider-cego: ele só resolve em OpenRouter. Com chave Anthropic dá\n * 404, com bearer OAuth dá 401, e em ambos o goal queimava 3 turnos inteiros antes de falhar com\n * razão enganosa. O agent-builder já contornava isso derivando por conta própria; o conhecimento\n * pertence aqui.\n */\n judgeModel?: string;\n /**\n * M80 — o modelo do agente CONDUZIDO. É a base da derivação: um judge que roda no mesmo modelo do\n * chat funciona onde o chat funciona.\n */\n agentModel?: string;\n /** Override env. Default `process.env.OPENROUTER_API_KEY` (EC-A). */\n apiKey?: string;\n}\n\n/**\n * M80 — a credencial ou o modelo do judge não servem: 401/404.\n *\n * Falha RÁPIDA por design. `rules/error-handling.md § 2` separa recuperável de irrecuperável, e um\n * modelo inexistente não passa a existir no retry — dobrar isso em `{parseFailed: true}` fazia o loop\n * tentar três vezes e reportar \"failed\" por limite de falhas consecutivas, escondendo que a causa era\n * credencial. Falha lenta e opaca trocada por rápida e clara.\n *\n * Falha de PARSE e erro de rede continuam dobrados: são recuperáveis, e o loop já decide por falhas\n * consecutivas.\n */\nexport class JudgeCredentialError extends TheokitAgentError {\n override readonly name = \"JudgeCredentialError\";\n\n constructor(\n readonly httpStatus: number,\n readonly judgeModel: string,\n cause: unknown,\n ) {\n super(\n `judge unavailable: model \"${judgeModel}\" returned ${String(httpStatus)}. ` +\n \"Pass `judgeModel`/`apiKey` that resolve for this provider, or omit `judgeModel` to derive \" +\n \"it from the agent being driven.\",\n { code: \"judge_credential\", cause, isRetryable: false },\n );\n }\n}\n\n/** Extrai o status HTTP de um erro de provider, quando ele o carrega. */\nfunction statusHttpDe(err: unknown): number | undefined {\n const s =\n (err as { status?: unknown; statusCode?: unknown }).status ??\n (err as { statusCode?: unknown }).statusCode;\n if (typeof s === \"number\") return s;\n const m = /\\b(401|403|404)\\b/.exec(err instanceof Error ? err.message : String(err));\n return m?.[1] !== undefined ? Number(m[1]) : undefined;\n}\n\n/** Dependencies injected so `judge-call.ts` stays free of `Agent` import. */\nexport interface JudgeDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Run the judge auxiliary agent and parse the verdict. Always returns a\n * `JudgeResult` — failures are folded into `{ parseFailed: true,\n * verdict: \"continue\" }` so the loop can decide based on consecutive\n * failures (ADR D121).\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: judge call must (1) check env or override, (2) catch errors as fail-safe, (3) ensure aux dispose runs once regardless of outcome — three concerns linearly arranged, harm clarity to extract.\nexport async function judgeCallImpl(\n ctx: JudgeContext,\n options: JudgeOptions | undefined,\n deps: JudgeDeps,\n): Promise<JudgeResult> {\n const prompt = composeJudgePrompt(ctx);\n // EC-A: single env source — OpenRouter only. No multi-provider fallback.\n const apiKey = options?.apiKey ?? process.env.OPENROUTER_API_KEY;\n if (apiKey === undefined) {\n return {\n verdict: \"continue\",\n reason:\n \"judge unavailable: OPENROUTER_API_KEY missing and no override passed via options.apiKey\",\n parseFailed: true,\n };\n }\n\n // M80 — precedência: explícito > modelo do agente conduzido > o literal histórico. O literal só\n // sobrevive como último recurso, para não quebrar quem nunca passou nenhum dos dois.\n const judgeModel = options?.judgeModel ?? options?.agentModel ?? \"openai/gpt-4o-mini\";\n let auxAgent: SDKAgent | undefined;\n try {\n auxAgent = await deps.create({\n apiKey,\n model: { id: judgeModel },\n tools: [],\n local: {},\n metadata: { forkOrigin: \"judge\" },\n } as AgentOptions);\n const run = await auxAgent.send(prompt);\n const result = await run.wait();\n return parseVerdict(result.result ?? \"\");\n } catch (err) {\n // M80 — 401/403/404 são de credencial/modelo: irrecuperáveis, falham rápido e tipado. Todo o\n // resto (rede, timeout, 5xx) segue dobrado, porque É recuperável e o loop já decide por falhas\n // consecutivas.\n const status = statusHttpDe(err);\n if (status === 401 || status === 403 || status === 404) {\n throw new JudgeCredentialError(status, judgeModel, err);\n }\n return {\n verdict: \"continue\",\n reason: `judge call failed: ${err instanceof Error ? err.message : String(err)}`,\n parseFailed: true,\n };\n } finally {\n if (auxAgent !== undefined) {\n try {\n await auxAgent.dispose();\n } catch {\n // dispose errors are non-fatal; judge result is already prepared\n }\n }\n }\n}\n\n/**\n * Build the strict-format prompt the judge expects.\n *\n * @internal\n */\nexport function composeJudgePrompt(ctx: JudgeContext): string {\n const subgoals =\n ctx.subgoals !== undefined && ctx.subgoals.length > 0 ? ctx.subgoals.join(\", \") : \"(none)\";\n return `You are a goal judge. Determine if this goal is satisfied.\n\nGoal: ${ctx.goal}\nSubgoals: ${subgoals}\nLast agent response: ${ctx.lastResponse}\n\nRespond with EXACTLY one of:\n- DONE: <reason>\n- CONTINUE: <what's left>\n- SKIPPED: <why not applicable>\n\nBe strict. If unclear, prefer CONTINUE.`;\n}\n"]}
@@ -1,9 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ var chunkA44COQJJ_cjs = require('./chunk-A44COQJJ.cjs');
4
+ require('./chunk-BEURCLDV.cjs');
5
+
3
6
  // src/internal/judge/parse-verdict.ts
4
7
  var DONE_PREFIX = "DONE:";
5
8
  var CONTINUE_PREFIX = "CONTINUE:";
6
9
  var SKIPPED_PREFIX = "SKIPPED:";
10
+ var BLOCKED_PREFIX = "BLOCKED:";
7
11
  function parseVerdict(text) {
8
12
  const trimmed = text.trim();
9
13
  if (trimmed.startsWith(DONE_PREFIX)) {
@@ -20,6 +24,13 @@ function parseVerdict(text) {
20
24
  parseFailed: false
21
25
  };
22
26
  }
27
+ if (trimmed.startsWith(BLOCKED_PREFIX)) {
28
+ return {
29
+ verdict: "blocked",
30
+ reason: trimmed.slice(BLOCKED_PREFIX.length).trim(),
31
+ parseFailed: false
32
+ };
33
+ }
23
34
  if (trimmed.startsWith(SKIPPED_PREFIX)) {
24
35
  return {
25
36
  verdict: "skipped",
@@ -35,6 +46,25 @@ function parseVerdict(text) {
35
46
  }
36
47
 
37
48
  // src/internal/judge/judge-call.ts
49
+ var JudgeCredentialError = class extends chunkA44COQJJ_cjs.TheokitAgentError {
50
+ constructor(httpStatus, judgeModel, cause) {
51
+ super(
52
+ `judge unavailable: model "${judgeModel}" returned ${String(httpStatus)}. Pass \`judgeModel\`/\`apiKey\` that resolve for this provider, or omit \`judgeModel\` to derive it from the agent being driven.`,
53
+ { code: "judge_credential", cause, isRetryable: false }
54
+ );
55
+ this.httpStatus = httpStatus;
56
+ this.judgeModel = judgeModel;
57
+ }
58
+ httpStatus;
59
+ judgeModel;
60
+ name = "JudgeCredentialError";
61
+ };
62
+ function statusHttpDe(err) {
63
+ const s = err.status ?? err.statusCode;
64
+ if (typeof s === "number") return s;
65
+ const m = /\b(401|403|404)\b/.exec(err instanceof Error ? err.message : String(err));
66
+ return m?.[1] !== void 0 ? Number(m[1]) : void 0;
67
+ }
38
68
  async function judgeCallImpl(ctx, options, deps) {
39
69
  const prompt = composeJudgePrompt(ctx);
40
70
  const apiKey = options?.apiKey ?? process.env.OPENROUTER_API_KEY;
@@ -45,7 +75,7 @@ async function judgeCallImpl(ctx, options, deps) {
45
75
  parseFailed: true
46
76
  };
47
77
  }
48
- const judgeModel = options?.judgeModel ?? "openai/gpt-4o-mini";
78
+ const judgeModel = options?.judgeModel ?? options?.agentModel ?? "openai/gpt-4o-mini";
49
79
  let auxAgent;
50
80
  try {
51
81
  auxAgent = await deps.create({
@@ -59,6 +89,10 @@ async function judgeCallImpl(ctx, options, deps) {
59
89
  const result = await run.wait();
60
90
  return parseVerdict(result.result ?? "");
61
91
  } catch (err) {
92
+ const status = statusHttpDe(err);
93
+ if (status === 401 || status === 403 || status === 404) {
94
+ throw new JudgeCredentialError(status, judgeModel, err);
95
+ }
62
96
  return {
63
97
  verdict: "continue",
64
98
  reason: `judge call failed: ${err instanceof Error ? err.message : String(err)}`,
@@ -89,7 +123,8 @@ Respond with EXACTLY one of:
89
123
  Be strict. If unclear, prefer CONTINUE.`;
90
124
  }
91
125
 
126
+ exports.JudgeCredentialError = JudgeCredentialError;
92
127
  exports.composeJudgePrompt = composeJudgePrompt;
93
128
  exports.judgeCallImpl = judgeCallImpl;
94
- //# sourceMappingURL=judge-call-7CF7D334.cjs.map
95
- //# sourceMappingURL=judge-call-7CF7D334.cjs.map
129
+ //# sourceMappingURL=judge-call-QG4WZ7F3.cjs.map
130
+ //# sourceMappingURL=judge-call-QG4WZ7F3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/judge/parse-verdict.ts","../src/internal/judge/judge-call.ts"],"names":["TheokitAgentError"],"mappings":"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","file":"judge-call-QG4WZ7F3.cjs","sourcesContent":["/**\n * Pure verdict parser (T2.1, ADRs D120-D121).\n *\n * Strict prefix matching against `DONE:`, `CONTINUE:`, `SKIPPED:`. Reason\n * is the suffix, trimmed. Anything else is fail-safe: verdict = `continue`,\n * `parseFailed: true` — caller's max-consecutive-failure cap stops the\n * loop after N flakes.\n *\n * @internal\n */\n\nimport type { JudgeResult } from \"./types.js\";\n\nconst DONE_PREFIX = \"DONE:\";\nconst CONTINUE_PREFIX = \"CONTINUE:\";\nconst SKIPPED_PREFIX = \"SKIPPED:\";\n/** M80 — o judge agora pode declarar impossibilidade, não só \"continue\". */\nconst BLOCKED_PREFIX = \"BLOCKED:\";\n\nexport function parseVerdict(text: string): JudgeResult {\n const trimmed = text.trim();\n\n if (trimmed.startsWith(DONE_PREFIX)) {\n return {\n verdict: \"done\",\n reason: trimmed.slice(DONE_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(CONTINUE_PREFIX)) {\n return {\n verdict: \"continue\",\n reason: trimmed.slice(CONTINUE_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(BLOCKED_PREFIX)) {\n return {\n verdict: \"blocked\",\n reason: trimmed.slice(BLOCKED_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(SKIPPED_PREFIX)) {\n return {\n verdict: \"skipped\",\n reason: trimmed.slice(SKIPPED_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n\n // Fail-safe: ADR D121 — prefer \"continue\" so we don't stop prematurely.\n // The runUntil loop counts consecutive parseFailed responses and bails\n // after `maxConsecutiveJudgeFailures` (default 3).\n return {\n verdict: \"continue\",\n reason: `judge response malformed: \"${trimmed.slice(0, 100)}\"`,\n parseFailed: true,\n };\n}\n","import { TheokitAgentError } from \"../../errors.js\";\n/**\n * Judge call primitive (T2.2, ADRs D119-D121).\n *\n * Instantiates a short-lived auxiliary agent that evaluates whether a\n * goal is satisfied. The auxiliary judge runs with `tools: []` and a\n * cheap model (default `openai/gpt-4o-mini`) — see ADR D119. The judge\n * model needs only API access; we read `OPENROUTER_API_KEY` directly\n * from the environment (EC-A — single source of truth) and let the\n * caller override via {@link JudgeOptions.apiKey} for Anthropic or\n * direct-OpenAI environments.\n *\n * NOTE: judge aux agents created from inside a `forkAgent` context will\n * inherit the parent fork's whitelist via AsyncLocalStorage (EC-J).\n * `tools: []` keeps this benign today; future callers that add tools to\n * a judge should be aware.\n *\n * @internal\n */\n\nimport type { AgentOptions, SDKAgent } from \"../../types/agent.js\";\nimport { parseVerdict } from \"./parse-verdict.js\";\nimport type { JudgeResult } from \"./types.js\";\n\n/** Inputs to the judge — pure data. */\nexport interface JudgeContext {\n goal: string;\n lastResponse: string;\n subgoals?: string[];\n}\n\n/** Caller-supplied tuning knobs for the judge call. */\nexport interface JudgeOptions {\n /**\n * Judge model identifier. Quando ausente, DERIVA de {@link agentModel} — e só cai no literal\n * `\"openai/gpt-4o-mini\"` se nem esse for informado.\n *\n * M80 — o default fixo era provider-cego: ele só resolve em OpenRouter. Com chave Anthropic dá\n * 404, com bearer OAuth dá 401, e em ambos o goal queimava 3 turnos inteiros antes de falhar com\n * razão enganosa. O agent-builder já contornava isso derivando por conta própria; o conhecimento\n * pertence aqui.\n */\n judgeModel?: string;\n /**\n * M80 — o modelo do agente CONDUZIDO. É a base da derivação: um judge que roda no mesmo modelo do\n * chat funciona onde o chat funciona.\n */\n agentModel?: string;\n /** Override env. Default `process.env.OPENROUTER_API_KEY` (EC-A). */\n apiKey?: string;\n}\n\n/**\n * M80 — a credencial ou o modelo do judge não servem: 401/404.\n *\n * Falha RÁPIDA por design. `rules/error-handling.md § 2` separa recuperável de irrecuperável, e um\n * modelo inexistente não passa a existir no retry — dobrar isso em `{parseFailed: true}` fazia o loop\n * tentar três vezes e reportar \"failed\" por limite de falhas consecutivas, escondendo que a causa era\n * credencial. Falha lenta e opaca trocada por rápida e clara.\n *\n * Falha de PARSE e erro de rede continuam dobrados: são recuperáveis, e o loop já decide por falhas\n * consecutivas.\n */\nexport class JudgeCredentialError extends TheokitAgentError {\n override readonly name = \"JudgeCredentialError\";\n\n constructor(\n readonly httpStatus: number,\n readonly judgeModel: string,\n cause: unknown,\n ) {\n super(\n `judge unavailable: model \"${judgeModel}\" returned ${String(httpStatus)}. ` +\n \"Pass `judgeModel`/`apiKey` that resolve for this provider, or omit `judgeModel` to derive \" +\n \"it from the agent being driven.\",\n { code: \"judge_credential\", cause, isRetryable: false },\n );\n }\n}\n\n/** Extrai o status HTTP de um erro de provider, quando ele o carrega. */\nfunction statusHttpDe(err: unknown): number | undefined {\n const s =\n (err as { status?: unknown; statusCode?: unknown }).status ??\n (err as { statusCode?: unknown }).statusCode;\n if (typeof s === \"number\") return s;\n const m = /\\b(401|403|404)\\b/.exec(err instanceof Error ? err.message : String(err));\n return m?.[1] !== undefined ? Number(m[1]) : undefined;\n}\n\n/** Dependencies injected so `judge-call.ts` stays free of `Agent` import. */\nexport interface JudgeDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Run the judge auxiliary agent and parse the verdict. Always returns a\n * `JudgeResult` — failures are folded into `{ parseFailed: true,\n * verdict: \"continue\" }` so the loop can decide based on consecutive\n * failures (ADR D121).\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: judge call must (1) check env or override, (2) catch errors as fail-safe, (3) ensure aux dispose runs once regardless of outcome — three concerns linearly arranged, harm clarity to extract.\nexport async function judgeCallImpl(\n ctx: JudgeContext,\n options: JudgeOptions | undefined,\n deps: JudgeDeps,\n): Promise<JudgeResult> {\n const prompt = composeJudgePrompt(ctx);\n // EC-A: single env source — OpenRouter only. No multi-provider fallback.\n const apiKey = options?.apiKey ?? process.env.OPENROUTER_API_KEY;\n if (apiKey === undefined) {\n return {\n verdict: \"continue\",\n reason:\n \"judge unavailable: OPENROUTER_API_KEY missing and no override passed via options.apiKey\",\n parseFailed: true,\n };\n }\n\n // M80 — precedência: explícito > modelo do agente conduzido > o literal histórico. O literal só\n // sobrevive como último recurso, para não quebrar quem nunca passou nenhum dos dois.\n const judgeModel = options?.judgeModel ?? options?.agentModel ?? \"openai/gpt-4o-mini\";\n let auxAgent: SDKAgent | undefined;\n try {\n auxAgent = await deps.create({\n apiKey,\n model: { id: judgeModel },\n tools: [],\n local: {},\n metadata: { forkOrigin: \"judge\" },\n } as AgentOptions);\n const run = await auxAgent.send(prompt);\n const result = await run.wait();\n return parseVerdict(result.result ?? \"\");\n } catch (err) {\n // M80 — 401/403/404 são de credencial/modelo: irrecuperáveis, falham rápido e tipado. Todo o\n // resto (rede, timeout, 5xx) segue dobrado, porque É recuperável e o loop já decide por falhas\n // consecutivas.\n const status = statusHttpDe(err);\n if (status === 401 || status === 403 || status === 404) {\n throw new JudgeCredentialError(status, judgeModel, err);\n }\n return {\n verdict: \"continue\",\n reason: `judge call failed: ${err instanceof Error ? err.message : String(err)}`,\n parseFailed: true,\n };\n } finally {\n if (auxAgent !== undefined) {\n try {\n await auxAgent.dispose();\n } catch {\n // dispose errors are non-fatal; judge result is already prepared\n }\n }\n }\n}\n\n/**\n * Build the strict-format prompt the judge expects.\n *\n * @internal\n */\nexport function composeJudgePrompt(ctx: JudgeContext): string {\n const subgoals =\n ctx.subgoals !== undefined && ctx.subgoals.length > 0 ? ctx.subgoals.join(\", \") : \"(none)\";\n return `You are a goal judge. Determine if this goal is satisfied.\n\nGoal: ${ctx.goal}\nSubgoals: ${subgoals}\nLast agent response: ${ctx.lastResponse}\n\nRespond with EXACTLY one of:\n- DONE: <reason>\n- CONTINUE: <what's left>\n- SKIPPED: <why not applicable>\n\nBe strict. If unclear, prefer CONTINUE.`;\n}\n"]}
@@ -98,6 +98,15 @@ async function* runUntilImpl(agent, goal, options, deps) {
98
98
  finalResponse: lastResponse || void 0
99
99
  };
100
100
  }
101
+ if (judgment.verdict === "blocked") {
102
+ yield { type: "status_change", status: "blocked", reason: judgment.reason };
103
+ return {
104
+ status: "blocked",
105
+ turnsUsed: turn,
106
+ tokensUsed,
107
+ finalResponse: lastResponse || void 0
108
+ };
109
+ }
101
110
  if (judgment.verdict === "skipped") {
102
111
  yield {
103
112
  type: "status_change",
@@ -167,5 +176,5 @@ ${lastResponse.slice(-1e3)}`
167
176
 
168
177
  exports.composeContinuation = composeContinuation;
169
178
  exports.runUntilImpl = runUntilImpl;
170
- //# sourceMappingURL=run-until-DB3LVGZS.cjs.map
171
- //# sourceMappingURL=run-until-DB3LVGZS.cjs.map
179
+ //# sourceMappingURL=run-until-PNO3QQLI.cjs.map
180
+ //# sourceMappingURL=run-until-PNO3QQLI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/runtime/lifecycle/run-until.ts"],"names":["GOAL_CONTINUATION_MARKER"],"mappings":"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","file":"run-until-PNO3QQLI.cjs","sourcesContent":["/**\n * Goal-driven Ralph loop (T3.2, ADRs D115-D121).\n *\n * `runUntilImpl` is an `AsyncGenerator<GoalEvent, GoalResult, void>`:\n * yields events as the loop progresses, returns the final result when\n * the goal completes, fails, or is paused. The auxiliary judge model is\n * injected via `deps.judge` so the generator stays free of the `Agent`\n * façade import.\n *\n * EC-C fix: pre-aborted signals emit only `[paused]`, not `[active, paused]`.\n * EC-D: `maxTurns: 0` is supported (vacuous yield active → failed).\n *\n * @internal\n */\n\nimport type { SDKAgent } from \"../../../types/agent.js\";\nimport type { GoalEvent, GoalOptions, GoalResult } from \"../../../types/goal-events.js\";\nimport type { JudgeContext, JudgeOptions } from \"../../judge/judge-call.js\";\nimport type { JudgeResult } from \"../../judge/types.js\";\nimport { GOAL_CONTINUATION_MARKER } from \"./goal-marker.js\";\n\n/** DI contract: the judge is the only external touchpoint. */\nexport interface RunUntilDeps {\n judge: (ctx: JudgeContext, opts?: JudgeOptions) => Promise<JudgeResult>;\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: the goal-loop interleaves turn-start, send, judge, continuation, abort-check, and failure-bail — extracting helpers harms the linear narrative.\nexport async function* runUntilImpl(\n agent: SDKAgent,\n goal: string,\n options: GoalOptions | undefined,\n deps: RunUntilDeps,\n): AsyncGenerator<GoalEvent, GoalResult, void> {\n const maxTurns = options?.maxTurns ?? 20;\n const maxFails = options?.maxConsecutiveJudgeFailures ?? 3;\n const tokenBudget = options?.tokenBudget; // M55 — undefined ⇒ ilimitado\n const signal = options?.signal;\n // Use a function (not direct property access) so TS does not narrow\n // `signal.aborted` to `false | undefined` after the initial check.\n // AbortSignal.aborted is a getter that can flip true between calls.\n // biome-ignore lint/complexity/useOptionalChain: optional-chain would re-narrow signal?.aborted to `false | undefined` after the first check, defeating the purpose of this helper.\n const isAborted = (): boolean => signal !== undefined && signal.aborted;\n let turn = 0;\n let consecutiveFailures = 0;\n let tokensUsed = 0; // M55 — soma observada (0 se usage ausente — fail-open)\n let lastResponse = \"\";\n\n // EC-C: signal already aborted BEFORE first event → emit only [paused].\n if (isAborted()) {\n yield {\n type: \"status_change\",\n status: \"paused\",\n reason: \"aborted via AbortSignal before first turn\",\n };\n return { status: \"paused\", turnsUsed: 0, tokensUsed, finalResponse: undefined };\n }\n\n yield { type: \"status_change\", status: \"active\", reason: \"Goal started\" };\n\n while (turn < maxTurns) {\n if (isAborted()) {\n yield { type: \"status_change\", status: \"paused\", reason: \"aborted via AbortSignal\" };\n return {\n status: \"paused\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n\n turn += 1;\n yield { type: \"turn_start\", turn, goal };\n\n const continuationPrompt = turn === 1 ? goal : composeContinuation(goal, lastResponse);\n\n const run = await agent.send(continuationPrompt);\n // M55 review HIGH — thread the abort INTO the in-flight run: without this, Esc mid-turn is\n // cosmetic (the turn keeps mutating the workspace until it finishes on its own). `run.cancel()`\n // aborts the stream + in-flight tool calls (types/run.ts contract).\n const cancelOnAbort = (): void => {\n void (run as { cancel?: () => Promise<void> }).cancel?.();\n };\n if (signal !== undefined) {\n if (signal.aborted) cancelOnAbort();\n else signal.addEventListener(\"abort\", cancelOnAbort, { once: true });\n }\n const result = await run.wait();\n if (signal !== undefined) signal.removeEventListener(\"abort\", cancelOnAbort);\n lastResponse = result.result ?? \"\";\n // M55 — token accounting fail-open: só soma quando o run reporta usage.\n const turnTokens = (result as { usage?: { totalTokens?: number } }).usage?.totalTokens;\n if (typeof turnTokens === \"number\") tokensUsed += turnTokens;\n // Re-check aborted right after the turn lands: a cancelled turn must NOT spend a judge call.\n if (isAborted()) {\n yield { type: \"status_change\", status: \"paused\", reason: \"aborted via AbortSignal\" };\n return {\n status: \"paused\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n yield { type: \"agent_response\", turn, content: lastResponse };\n\n const judgeOpts: JudgeOptions = {};\n if (options?.judgeModel !== undefined) judgeOpts.judgeModel = options.judgeModel;\n if (options?.judgeApiKey !== undefined) judgeOpts.apiKey = options.judgeApiKey;\n const judgeCtx: JudgeContext = { goal, lastResponse };\n if (options?.subgoals !== undefined) judgeCtx.subgoals = options.subgoals;\n const judgment = await deps.judge(judgeCtx, judgeOpts);\n yield {\n type: \"judge_verdict\",\n turn,\n verdict: judgment.verdict,\n reason: judgment.reason,\n parseFailed: judgment.parseFailed,\n };\n\n if (judgment.parseFailed) {\n consecutiveFailures += 1;\n if (consecutiveFailures >= maxFails) {\n yield {\n type: \"status_change\",\n status: \"failed\",\n reason: `judge model too unreliable (${consecutiveFailures} parse failures in a row)`,\n };\n return {\n status: \"failed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n } else {\n consecutiveFailures = 0;\n }\n\n if (judgment.verdict === \"done\") {\n yield { type: \"status_change\", status: \"completed\", reason: judgment.reason };\n return {\n status: \"completed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n // M80 — o braço que faltava. Sem ele, um judge que reconhecesse impossibilidade só podia dizer\n // \"continue\", e o loop repetia o mesmo turno até estourar o orçamento — reportando `failed` por\n // limite em vez de `blocked` por impossibilidade. Duas causas distintas com o mesmo desfecho\n // visível, e o consumidor precisava reconciliar depois do loop para distingui-las.\n if (judgment.verdict === \"blocked\") {\n yield { type: \"status_change\", status: \"blocked\", reason: judgment.reason };\n return {\n status: \"blocked\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n if (judgment.verdict === \"skipped\") {\n yield {\n type: \"status_change\",\n status: \"completed\",\n reason: `skipped: ${judgment.reason}`,\n };\n return {\n status: \"completed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n\n // M55 — checagem de token budget APÓS o turno (Codex: wind-down suave, para o loop).\n if (tokenBudget !== undefined && tokensUsed >= tokenBudget) {\n yield {\n type: \"status_change\",\n status: \"budget_limited\",\n reason: `token budget (${tokenBudget}) reached: ${tokensUsed} used`,\n };\n return {\n status: \"budget_limited\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n\n yield { type: \"continuation\", turn, prompt: continuationPrompt };\n }\n\n yield {\n type: \"status_change\",\n status: \"failed\",\n reason: `max turns (${maxTurns}) exhausted`,\n };\n return {\n status: \"failed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n}\n\n/**\n * Build the continuation user message for turns 2+. Keeps last response\n * preview short so we don't bloat the prompt cache.\n *\n * @internal\n */\n\nexport function composeContinuation(goal: string, lastResponse: string): string {\n // M55 — Codex-faithful continuation (ext/goal templates/goals/continuation.md): keep the FULL\n // objective intact, work from current-state evidence, and audit completion requirement-by-requirement\n // before declaring done. Improves the quality of what the judge then evaluates.\n return [\n GOAL_CONTINUATION_MARKER,\n \"Continue working toward the active goal.\",\n \"\",\n `<objective>\\n${goal}\\n</objective>`,\n \"\",\n \"Continuation behavior:\",\n \"- This goal persists across turns. Keep the full objective intact; if it cannot be finished now,\",\n \" make concrete progress toward the real requested end state and do not redefine success around a\",\n \" smaller or easier task.\",\n \"\",\n \"Work from evidence:\",\n \"- Use the current worktree and external state as authoritative. Inspect the current state before\",\n \" relying on it. Improve, replace, or remove existing work as needed to satisfy the actual objective.\",\n \"\",\n \"Completion audit:\",\n \"- Before deciding the goal is achieved, treat completion as unproven and verify it against the actual\",\n \" current state, requirement by requirement. Treat uncertain or indirect evidence as not achieved.\",\n \"\",\n `Your last response was:\\n${lastResponse.slice(-1000)}`,\n ].join(\"\\n\");\n}\n"]}
@@ -96,6 +96,15 @@ async function* runUntilImpl(agent, goal, options, deps) {
96
96
  finalResponse: lastResponse || void 0
97
97
  };
98
98
  }
99
+ if (judgment.verdict === "blocked") {
100
+ yield { type: "status_change", status: "blocked", reason: judgment.reason };
101
+ return {
102
+ status: "blocked",
103
+ turnsUsed: turn,
104
+ tokensUsed,
105
+ finalResponse: lastResponse || void 0
106
+ };
107
+ }
99
108
  if (judgment.verdict === "skipped") {
100
109
  yield {
101
110
  type: "status_change",
@@ -164,5 +173,5 @@ ${lastResponse.slice(-1e3)}`
164
173
  }
165
174
 
166
175
  export { composeContinuation, runUntilImpl };
167
- //# sourceMappingURL=run-until-2PX4QBHZ.js.map
168
- //# sourceMappingURL=run-until-2PX4QBHZ.js.map
176
+ //# sourceMappingURL=run-until-XLHEHRQM.js.map
177
+ //# sourceMappingURL=run-until-XLHEHRQM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/runtime/lifecycle/run-until.ts"],"names":[],"mappings":";;;AA2BA,gBAAuB,YAAA,CACrB,KAAA,EACA,IAAA,EACA,OAAA,EACA,IAAA,EAC6C;AAC7C,EAAA,MAAM,QAAA,GAAW,SAAS,QAAA,IAAY,EAAA;AACtC,EAAA,MAAM,QAAA,GAAW,SAAS,2BAAA,IAA+B,CAAA;AACzD,EAAA,MAAM,cAAc,OAAA,EAAS,WAAA;AAC7B,EAAA,MAAM,SAAS,OAAA,EAAS,MAAA;AAKxB,EAAA,MAAM,SAAA,GAAY,MAAe,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,OAAA;AAChE,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,mBAAA,GAAsB,CAAA;AAC1B,EAAA,IAAI,UAAA,GAAa,CAAA;AACjB,EAAA,IAAI,YAAA,GAAe,EAAA;AAGnB,EAAA,IAAI,WAAU,EAAG;AACf,IAAA,MAAM;AAAA,MACJ,IAAA,EAAM,eAAA;AAAA,MACN,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACV;AACA,IAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,WAAW,CAAA,EAAG,UAAA,EAAY,eAAe,MAAA,EAAU;AAAA,EAChF;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,eAAA,EAAiB,MAAA,EAAQ,QAAA,EAAU,QAAQ,cAAA,EAAe;AAExE,EAAA,OAAO,OAAO,QAAA,EAAU;AACtB,IAAA,IAAI,WAAU,EAAG;AACf,MAAA,MAAM,EAAE,IAAA,EAAM,eAAA,EAAiB,MAAA,EAAQ,QAAA,EAAU,QAAQ,yBAAA,EAA0B;AACnF,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,QAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,UAAA;AAAA,QACA,eAAe,YAAA,IAAgB;AAAA,OACjC;AAAA,IACF;AAEA,IAAA,IAAA,IAAQ,CAAA;AACR,IAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,IAAA,EAAK;AAEvC,IAAA,MAAM,qBAAqB,IAAA,KAAS,CAAA,GAAI,IAAA,GAAO,mBAAA,CAAoB,MAAM,YAAY,CAAA;AAErF,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,CAAK,kBAAkB,CAAA;AAI/C,IAAA,MAAM,gBAAgB,MAAY;AAChC,MAAA,KAAM,IAAyC,MAAA,IAAS;AAAA,IAC1D,CAAA;AACA,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,IAAI,MAAA,CAAO,SAAS,aAAA,EAAc;AAAA,kBACtB,gBAAA,CAAiB,OAAA,EAAS,eAAe,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IACrE;AACA,IAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,IAAA,EAAK;AAC9B,IAAA,IAAI,MAAA,KAAW,MAAA,EAAW,MAAA,CAAO,mBAAA,CAAoB,SAAS,aAAa,CAAA;AAC3E,IAAA,YAAA,GAAe,OAAO,MAAA,IAAU,EAAA;AAEhC,IAAA,MAAM,UAAA,GAAc,OAAgD,KAAA,EAAO,WAAA;AAC3E,IAAA,IAAI,OAAO,UAAA,KAAe,QAAA,EAAU,UAAA,IAAc,UAAA;AAElD,IAAA,IAAI,WAAU,EAAG;AACf,MAAA,MAAM,EAAE,IAAA,EAAM,eAAA,EAAiB,MAAA,EAAQ,QAAA,EAAU,QAAQ,yBAAA,EAA0B;AACnF,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,QAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,UAAA;AAAA,QACA,eAAe,YAAA,IAAgB;AAAA,OACjC;AAAA,IACF;AACA,IAAA,MAAM,EAAE,IAAA,EAAM,gBAAA,EAAkB,IAAA,EAAM,SAAS,YAAA,EAAa;AAE5D,IAAA,MAAM,YAA0B,EAAC;AACjC,IAAA,IAAI,OAAA,EAAS,UAAA,KAAe,MAAA,EAAW,SAAA,CAAU,aAAa,OAAA,CAAQ,UAAA;AACtE,IAAA,IAAI,OAAA,EAAS,WAAA,KAAgB,MAAA,EAAW,SAAA,CAAU,SAAS,OAAA,CAAQ,WAAA;AACnE,IAAA,MAAM,QAAA,GAAyB,EAAE,IAAA,EAAM,YAAA,EAAa;AACpD,IAAA,IAAI,OAAA,EAAS,QAAA,KAAa,MAAA,EAAW,QAAA,CAAS,WAAW,OAAA,CAAQ,QAAA;AACjE,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,KAAA,CAAM,UAAU,SAAS,CAAA;AACrD,IAAA,MAAM;AAAA,MACJ,IAAA,EAAM,eAAA;AAAA,MACN,IAAA;AAAA,MACA,SAAS,QAAA,CAAS,OAAA;AAAA,MAClB,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,aAAa,QAAA,CAAS;AAAA,KACxB;AAEA,IAAA,IAAI,SAAS,WAAA,EAAa;AACxB,MAAA,mBAAA,IAAuB,CAAA;AACvB,MAAA,IAAI,uBAAuB,QAAA,EAAU;AACnC,QAAA,MAAM;AAAA,UACJ,IAAA,EAAM,eAAA;AAAA,UACN,MAAA,EAAQ,QAAA;AAAA,UACR,MAAA,EAAQ,+BAA+B,mBAAmB,CAAA,yBAAA;AAAA,SAC5D;AACA,QAAA,OAAO;AAAA,UACL,MAAA,EAAQ,QAAA;AAAA,UACR,SAAA,EAAW,IAAA;AAAA,UACX,UAAA;AAAA,UACA,eAAe,YAAA,IAAgB;AAAA,SACjC;AAAA,MACF;AAAA,IACF,CAAA,MAAO;AACL,MAAA,mBAAA,GAAsB,CAAA;AAAA,IACxB;AAEA,IAAA,IAAI,QAAA,CAAS,YAAY,MAAA,EAAQ;AAC/B,MAAA,MAAM,EAAE,IAAA,EAAM,eAAA,EAAiB,QAAQ,WAAA,EAAa,MAAA,EAAQ,SAAS,MAAA,EAAO;AAC5E,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,WAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,UAAA;AAAA,QACA,eAAe,YAAA,IAAgB;AAAA,OACjC;AAAA,IACF;AAKA,IAAA,IAAI,QAAA,CAAS,YAAY,SAAA,EAAW;AAClC,MAAA,MAAM,EAAE,IAAA,EAAM,eAAA,EAAiB,QAAQ,SAAA,EAAW,MAAA,EAAQ,SAAS,MAAA,EAAO;AAC1E,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,SAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,UAAA;AAAA,QACA,eAAe,YAAA,IAAgB;AAAA,OACjC;AAAA,IACF;AACA,IAAA,IAAI,QAAA,CAAS,YAAY,SAAA,EAAW;AAClC,MAAA,MAAM;AAAA,QACJ,IAAA,EAAM,eAAA;AAAA,QACN,MAAA,EAAQ,WAAA;AAAA,QACR,MAAA,EAAQ,CAAA,SAAA,EAAY,QAAA,CAAS,MAAM,CAAA;AAAA,OACrC;AACA,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,WAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,UAAA;AAAA,QACA,eAAe,YAAA,IAAgB;AAAA,OACjC;AAAA,IACF;AAGA,IAAA,IAAI,WAAA,KAAgB,MAAA,IAAa,UAAA,IAAc,WAAA,EAAa;AAC1D,MAAA,MAAM;AAAA,QACJ,IAAA,EAAM,eAAA;AAAA,QACN,MAAA,EAAQ,gBAAA;AAAA,QACR,MAAA,EAAQ,CAAA,cAAA,EAAiB,WAAW,CAAA,WAAA,EAAc,UAAU,CAAA,KAAA;AAAA,OAC9D;AACA,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,gBAAA;AAAA,QACR,SAAA,EAAW,IAAA;AAAA,QACX,UAAA;AAAA,QACA,eAAe,YAAA,IAAgB;AAAA,OACjC;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,IAAA,EAAM,cAAA,EAAgB,IAAA,EAAM,QAAQ,kBAAA,EAAmB;AAAA,EACjE;AAEA,EAAA,MAAM;AAAA,IACJ,IAAA,EAAM,eAAA;AAAA,IACN,MAAA,EAAQ,QAAA;AAAA,IACR,MAAA,EAAQ,cAAc,QAAQ,CAAA,WAAA;AAAA,GAChC;AACA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,IAAA;AAAA,IACX,UAAA;AAAA,IACA,eAAe,YAAA,IAAgB;AAAA,GACjC;AACF;AASO,SAAS,mBAAA,CAAoB,MAAc,YAAA,EAA8B;AAI9E,EAAA,OAAO;AAAA,IACL,wBAAA;AAAA,IACA,0CAAA;AAAA,IACA,EAAA;AAAA,IACA,CAAA;AAAA,EAAgB,IAAI;AAAA,YAAA,CAAA;AAAA,IACpB,EAAA;AAAA,IACA,wBAAA;AAAA,IACA,kGAAA;AAAA,IACA,mGAAA;AAAA,IACA,2BAAA;AAAA,IACA,EAAA;AAAA,IACA,qBAAA;AAAA,IACA,kGAAA;AAAA,IACA,uGAAA;AAAA,IACA,EAAA;AAAA,IACA,mBAAA;AAAA,IACA,uGAAA;AAAA,IACA,oGAAA;AAAA,IACA,EAAA;AAAA,IACA,CAAA;AAAA,EAA4B,YAAA,CAAa,KAAA,CAAM,IAAK,CAAC,CAAA;AAAA,GACvD,CAAE,KAAK,IAAI,CAAA;AACb","file":"run-until-XLHEHRQM.js","sourcesContent":["/**\n * Goal-driven Ralph loop (T3.2, ADRs D115-D121).\n *\n * `runUntilImpl` is an `AsyncGenerator<GoalEvent, GoalResult, void>`:\n * yields events as the loop progresses, returns the final result when\n * the goal completes, fails, or is paused. The auxiliary judge model is\n * injected via `deps.judge` so the generator stays free of the `Agent`\n * façade import.\n *\n * EC-C fix: pre-aborted signals emit only `[paused]`, not `[active, paused]`.\n * EC-D: `maxTurns: 0` is supported (vacuous yield active → failed).\n *\n * @internal\n */\n\nimport type { SDKAgent } from \"../../../types/agent.js\";\nimport type { GoalEvent, GoalOptions, GoalResult } from \"../../../types/goal-events.js\";\nimport type { JudgeContext, JudgeOptions } from \"../../judge/judge-call.js\";\nimport type { JudgeResult } from \"../../judge/types.js\";\nimport { GOAL_CONTINUATION_MARKER } from \"./goal-marker.js\";\n\n/** DI contract: the judge is the only external touchpoint. */\nexport interface RunUntilDeps {\n judge: (ctx: JudgeContext, opts?: JudgeOptions) => Promise<JudgeResult>;\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: the goal-loop interleaves turn-start, send, judge, continuation, abort-check, and failure-bail — extracting helpers harms the linear narrative.\nexport async function* runUntilImpl(\n agent: SDKAgent,\n goal: string,\n options: GoalOptions | undefined,\n deps: RunUntilDeps,\n): AsyncGenerator<GoalEvent, GoalResult, void> {\n const maxTurns = options?.maxTurns ?? 20;\n const maxFails = options?.maxConsecutiveJudgeFailures ?? 3;\n const tokenBudget = options?.tokenBudget; // M55 — undefined ⇒ ilimitado\n const signal = options?.signal;\n // Use a function (not direct property access) so TS does not narrow\n // `signal.aborted` to `false | undefined` after the initial check.\n // AbortSignal.aborted is a getter that can flip true between calls.\n // biome-ignore lint/complexity/useOptionalChain: optional-chain would re-narrow signal?.aborted to `false | undefined` after the first check, defeating the purpose of this helper.\n const isAborted = (): boolean => signal !== undefined && signal.aborted;\n let turn = 0;\n let consecutiveFailures = 0;\n let tokensUsed = 0; // M55 — soma observada (0 se usage ausente — fail-open)\n let lastResponse = \"\";\n\n // EC-C: signal already aborted BEFORE first event → emit only [paused].\n if (isAborted()) {\n yield {\n type: \"status_change\",\n status: \"paused\",\n reason: \"aborted via AbortSignal before first turn\",\n };\n return { status: \"paused\", turnsUsed: 0, tokensUsed, finalResponse: undefined };\n }\n\n yield { type: \"status_change\", status: \"active\", reason: \"Goal started\" };\n\n while (turn < maxTurns) {\n if (isAborted()) {\n yield { type: \"status_change\", status: \"paused\", reason: \"aborted via AbortSignal\" };\n return {\n status: \"paused\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n\n turn += 1;\n yield { type: \"turn_start\", turn, goal };\n\n const continuationPrompt = turn === 1 ? goal : composeContinuation(goal, lastResponse);\n\n const run = await agent.send(continuationPrompt);\n // M55 review HIGH — thread the abort INTO the in-flight run: without this, Esc mid-turn is\n // cosmetic (the turn keeps mutating the workspace until it finishes on its own). `run.cancel()`\n // aborts the stream + in-flight tool calls (types/run.ts contract).\n const cancelOnAbort = (): void => {\n void (run as { cancel?: () => Promise<void> }).cancel?.();\n };\n if (signal !== undefined) {\n if (signal.aborted) cancelOnAbort();\n else signal.addEventListener(\"abort\", cancelOnAbort, { once: true });\n }\n const result = await run.wait();\n if (signal !== undefined) signal.removeEventListener(\"abort\", cancelOnAbort);\n lastResponse = result.result ?? \"\";\n // M55 — token accounting fail-open: só soma quando o run reporta usage.\n const turnTokens = (result as { usage?: { totalTokens?: number } }).usage?.totalTokens;\n if (typeof turnTokens === \"number\") tokensUsed += turnTokens;\n // Re-check aborted right after the turn lands: a cancelled turn must NOT spend a judge call.\n if (isAborted()) {\n yield { type: \"status_change\", status: \"paused\", reason: \"aborted via AbortSignal\" };\n return {\n status: \"paused\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n yield { type: \"agent_response\", turn, content: lastResponse };\n\n const judgeOpts: JudgeOptions = {};\n if (options?.judgeModel !== undefined) judgeOpts.judgeModel = options.judgeModel;\n if (options?.judgeApiKey !== undefined) judgeOpts.apiKey = options.judgeApiKey;\n const judgeCtx: JudgeContext = { goal, lastResponse };\n if (options?.subgoals !== undefined) judgeCtx.subgoals = options.subgoals;\n const judgment = await deps.judge(judgeCtx, judgeOpts);\n yield {\n type: \"judge_verdict\",\n turn,\n verdict: judgment.verdict,\n reason: judgment.reason,\n parseFailed: judgment.parseFailed,\n };\n\n if (judgment.parseFailed) {\n consecutiveFailures += 1;\n if (consecutiveFailures >= maxFails) {\n yield {\n type: \"status_change\",\n status: \"failed\",\n reason: `judge model too unreliable (${consecutiveFailures} parse failures in a row)`,\n };\n return {\n status: \"failed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n } else {\n consecutiveFailures = 0;\n }\n\n if (judgment.verdict === \"done\") {\n yield { type: \"status_change\", status: \"completed\", reason: judgment.reason };\n return {\n status: \"completed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n // M80 — o braço que faltava. Sem ele, um judge que reconhecesse impossibilidade só podia dizer\n // \"continue\", e o loop repetia o mesmo turno até estourar o orçamento — reportando `failed` por\n // limite em vez de `blocked` por impossibilidade. Duas causas distintas com o mesmo desfecho\n // visível, e o consumidor precisava reconciliar depois do loop para distingui-las.\n if (judgment.verdict === \"blocked\") {\n yield { type: \"status_change\", status: \"blocked\", reason: judgment.reason };\n return {\n status: \"blocked\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n if (judgment.verdict === \"skipped\") {\n yield {\n type: \"status_change\",\n status: \"completed\",\n reason: `skipped: ${judgment.reason}`,\n };\n return {\n status: \"completed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n\n // M55 — checagem de token budget APÓS o turno (Codex: wind-down suave, para o loop).\n if (tokenBudget !== undefined && tokensUsed >= tokenBudget) {\n yield {\n type: \"status_change\",\n status: \"budget_limited\",\n reason: `token budget (${tokenBudget}) reached: ${tokensUsed} used`,\n };\n return {\n status: \"budget_limited\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n }\n\n yield { type: \"continuation\", turn, prompt: continuationPrompt };\n }\n\n yield {\n type: \"status_change\",\n status: \"failed\",\n reason: `max turns (${maxTurns}) exhausted`,\n };\n return {\n status: \"failed\",\n turnsUsed: turn,\n tokensUsed,\n finalResponse: lastResponse || undefined,\n };\n}\n\n/**\n * Build the continuation user message for turns 2+. Keeps last response\n * preview short so we don't bloat the prompt cache.\n *\n * @internal\n */\n\nexport function composeContinuation(goal: string, lastResponse: string): string {\n // M55 — Codex-faithful continuation (ext/goal templates/goals/continuation.md): keep the FULL\n // objective intact, work from current-state evidence, and audit completion requirement-by-requirement\n // before declaring done. Improves the quality of what the judge then evaluates.\n return [\n GOAL_CONTINUATION_MARKER,\n \"Continue working toward the active goal.\",\n \"\",\n `<objective>\\n${goal}\\n</objective>`,\n \"\",\n \"Continuation behavior:\",\n \"- This goal persists across turns. Keep the full objective intact; if it cannot be finished now,\",\n \" make concrete progress toward the real requested end state and do not redefine success around a\",\n \" smaller or easier task.\",\n \"\",\n \"Work from evidence:\",\n \"- Use the current worktree and external state as authoritative. Inspect the current state before\",\n \" relying on it. Improve, replace, or remove existing work as needed to satisfy the actual objective.\",\n \"\",\n \"Completion audit:\",\n \"- Before deciding the goal is achieved, treat completion as unproven and verify it against the actual\",\n \" current state, requirement by requirement. Treat uncertain or indirect evidence as not achieved.\",\n \"\",\n `Your last response was:\\n${lastResponse.slice(-1000)}`,\n ].join(\"\\n\");\n}\n"]}
@@ -40,7 +40,8 @@ export type GoalEvent = {
40
40
  } | {
41
41
  type: "judge_verdict";
42
42
  turn: number;
43
- verdict: "done" | "continue" | "skipped";
43
+ /** M80 — `"blocked"` entrou: o judge pode declarar impossibilidade, não só "continue". */
44
+ verdict: "done" | "continue" | "skipped" | "blocked";
44
45
  reason: string;
45
46
  parseFailed: boolean;
46
47
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theokit/sdk",
3
- "version": "4.25.0",
3
+ "version": "4.26.0",
4
4
  "description": "TypeScript SDK for the Theo agent harness — same surface, local or cloud.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/usetheodev/theokit-sdk#readme",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/judge/parse-verdict.ts","../src/internal/judge/judge-call.ts"],"names":[],"mappings":"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","file":"judge-call-7CF7D334.cjs","sourcesContent":["/**\n * Pure verdict parser (T2.1, ADRs D120-D121).\n *\n * Strict prefix matching against `DONE:`, `CONTINUE:`, `SKIPPED:`. Reason\n * is the suffix, trimmed. Anything else is fail-safe: verdict = `continue`,\n * `parseFailed: true` — caller's max-consecutive-failure cap stops the\n * loop after N flakes.\n *\n * @internal\n */\n\nimport type { JudgeResult } from \"./types.js\";\n\nconst DONE_PREFIX = \"DONE:\";\nconst CONTINUE_PREFIX = \"CONTINUE:\";\nconst SKIPPED_PREFIX = \"SKIPPED:\";\n\nexport function parseVerdict(text: string): JudgeResult {\n const trimmed = text.trim();\n\n if (trimmed.startsWith(DONE_PREFIX)) {\n return {\n verdict: \"done\",\n reason: trimmed.slice(DONE_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(CONTINUE_PREFIX)) {\n return {\n verdict: \"continue\",\n reason: trimmed.slice(CONTINUE_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n if (trimmed.startsWith(SKIPPED_PREFIX)) {\n return {\n verdict: \"skipped\",\n reason: trimmed.slice(SKIPPED_PREFIX.length).trim(),\n parseFailed: false,\n };\n }\n\n // Fail-safe: ADR D121 — prefer \"continue\" so we don't stop prematurely.\n // The runUntil loop counts consecutive parseFailed responses and bails\n // after `maxConsecutiveJudgeFailures` (default 3).\n return {\n verdict: \"continue\",\n reason: `judge response malformed: \"${trimmed.slice(0, 100)}\"`,\n parseFailed: true,\n };\n}\n","/**\n * Judge call primitive (T2.2, ADRs D119-D121).\n *\n * Instantiates a short-lived auxiliary agent that evaluates whether a\n * goal is satisfied. The auxiliary judge runs with `tools: []` and a\n * cheap model (default `openai/gpt-4o-mini`) — see ADR D119. The judge\n * model needs only API access; we read `OPENROUTER_API_KEY` directly\n * from the environment (EC-A — single source of truth) and let the\n * caller override via {@link JudgeOptions.apiKey} for Anthropic or\n * direct-OpenAI environments.\n *\n * NOTE: judge aux agents created from inside a `forkAgent` context will\n * inherit the parent fork's whitelist via AsyncLocalStorage (EC-J).\n * `tools: []` keeps this benign today; future callers that add tools to\n * a judge should be aware.\n *\n * @internal\n */\n\nimport type { AgentOptions, SDKAgent } from \"../../types/agent.js\";\nimport { parseVerdict } from \"./parse-verdict.js\";\nimport type { JudgeResult } from \"./types.js\";\n\n/** Inputs to the judge — pure data. */\nexport interface JudgeContext {\n goal: string;\n lastResponse: string;\n subgoals?: string[];\n}\n\n/** Caller-supplied tuning knobs for the judge call. */\nexport interface JudgeOptions {\n /** Judge model identifier. Default `\"openai/gpt-4o-mini\"` (ADR D119). */\n judgeModel?: string;\n /** Override env. Default `process.env.OPENROUTER_API_KEY` (EC-A). */\n apiKey?: string;\n}\n\n/** Dependencies injected so `judge-call.ts` stays free of `Agent` import. */\nexport interface JudgeDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Run the judge auxiliary agent and parse the verdict. Always returns a\n * `JudgeResult` — failures are folded into `{ parseFailed: true,\n * verdict: \"continue\" }` so the loop can decide based on consecutive\n * failures (ADR D121).\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: judge call must (1) check env or override, (2) catch errors as fail-safe, (3) ensure aux dispose runs once regardless of outcome — three concerns linearly arranged, harm clarity to extract.\nexport async function judgeCallImpl(\n ctx: JudgeContext,\n options: JudgeOptions | undefined,\n deps: JudgeDeps,\n): Promise<JudgeResult> {\n const prompt = composeJudgePrompt(ctx);\n // EC-A: single env source — OpenRouter only. No multi-provider fallback.\n const apiKey = options?.apiKey ?? process.env.OPENROUTER_API_KEY;\n if (apiKey === undefined) {\n return {\n verdict: \"continue\",\n reason:\n \"judge unavailable: OPENROUTER_API_KEY missing and no override passed via options.apiKey\",\n parseFailed: true,\n };\n }\n\n const judgeModel = options?.judgeModel ?? \"openai/gpt-4o-mini\";\n let auxAgent: SDKAgent | undefined;\n try {\n auxAgent = await deps.create({\n apiKey,\n model: { id: judgeModel },\n tools: [],\n local: {},\n metadata: { forkOrigin: \"judge\" },\n } as AgentOptions);\n const run = await auxAgent.send(prompt);\n const result = await run.wait();\n return parseVerdict(result.result ?? \"\");\n } catch (err) {\n return {\n verdict: \"continue\",\n reason: `judge call failed: ${err instanceof Error ? err.message : String(err)}`,\n parseFailed: true,\n };\n } finally {\n if (auxAgent !== undefined) {\n try {\n await auxAgent.dispose();\n } catch {\n // dispose errors are non-fatal; judge result is already prepared\n }\n }\n }\n}\n\n/**\n * Build the strict-format prompt the judge expects.\n *\n * @internal\n */\nexport function composeJudgePrompt(ctx: JudgeContext): string {\n const subgoals =\n ctx.subgoals !== undefined && ctx.subgoals.length > 0 ? ctx.subgoals.join(\", \") : \"(none)\";\n return `You are a goal judge. Determine if this goal is satisfied.\n\nGoal: ${ctx.goal}\nSubgoals: ${subgoals}\nLast agent response: ${ctx.lastResponse}\n\nRespond with EXACTLY one of:\n- DONE: <reason>\n- CONTINUE: <what's left>\n- SKIPPED: <why not applicable>\n\nBe strict. If unclear, prefer CONTINUE.`;\n}\n"]}