@gajae-code/coding-agent 0.18.6 → 0.18.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +318 -1
- package/dist/types/async/job-manager.d.ts +1 -1
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/capability/skill.d.ts +2 -0
- package/dist/types/capability/types.d.ts +6 -0
- package/dist/types/cli/public-command-errors.d.ts +3 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/autorouting-tier-map.d.ts +348 -9
- package/dist/types/config/file-lock.d.ts +1 -0
- package/dist/types/config/model-bindings-applier.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +11 -3
- package/dist/types/config/model-registry.d.ts +4 -9
- package/dist/types/config/settings.d.ts +4 -0
- package/dist/types/config/skill-settings-defaults.d.ts +2 -0
- package/dist/types/cursor-delete-path.d.ts +1 -0
- package/dist/types/cursor-mcp-name.d.ts +8 -0
- package/dist/types/customization/inventory.d.ts +2 -0
- package/dist/types/debug/report-bundle-parent.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
- package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
- package/dist/types/discovery/helpers.d.ts +8 -3
- package/dist/types/export/html/css-color.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/types.d.ts +7 -0
- package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
- package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
- package/dist/types/extensibility/skill-management.d.ts +3 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
- package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
- package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +11 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
- package/dist/types/internal-urls/skill-path.d.ts +1 -0
- package/dist/types/lsp/workspace-path.d.ts +1 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
- package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
- package/dist/types/modes/controllers/input-controller.d.ts +9 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
- package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
- package/dist/types/progress/collect-project-progress.d.ts +38 -0
- package/dist/types/progress/progress-contract.d.ts +154 -0
- package/dist/types/progress/progress-snapshot.d.ts +11 -0
- package/dist/types/progress/project-progress.d.ts +141 -0
- package/dist/types/progress/render-progress.d.ts +28 -0
- package/dist/types/runtime-mcp/elicitation.d.ts +12 -0
- package/dist/types/runtime-mcp/oauth-public-url.d.ts +1 -0
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
- package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk/acp/adapter.d.ts +1 -1
- package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
- package/dist/types/sdk/broker/broker.d.ts +18 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +9 -0
- package/dist/types/sdk/broker/session-index.d.ts +12 -6
- package/dist/types/sdk/broker/task-artifact-owner-validation.d.ts +55 -0
- package/dist/types/sdk/bus/index.d.ts +12 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +3 -2
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/host/host.d.ts +6 -0
- package/dist/types/sdk/host/query/handlers.d.ts +3 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +9 -0
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +38 -9
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +36 -1
- package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
- package/dist/types/session/internal/task-artifact-owner-access.d.ts +19 -0
- package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +11 -0
- package/dist/types/session/session-manager.d.ts +31 -5
- package/dist/types/session/session-retirement.d.ts +71 -0
- package/dist/types/session/session-storage.d.ts +62 -48
- package/dist/types/session/session-transcript-header.d.ts +2 -0
- package/dist/types/session/task-artifact-owner-codec.d.ts +109 -0
- package/dist/types/session/task-artifact-owner-retirement.d.ts +7 -0
- package/dist/types/session/task-artifact-owner.d.ts +10 -0
- package/dist/types/setup/credential-auto-import.d.ts +1 -1
- package/dist/types/setup/credential-import.d.ts +6 -4
- package/dist/types/skill-state/active-state.d.ts +38 -0
- package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -1
- package/dist/types/tools/index.d.ts +3 -0
- package/dist/types/tools/python.d.ts +9 -1
- package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
- package/dist/types/tools/restricted-cwd.d.ts +1 -0
- package/dist/types/tools/todo-write.d.ts +6 -0
- package/dist/types/utils/tools-checksum.d.ts +7 -0
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +21 -0
- package/scripts/resident-memory-bench.ts +174 -20
- package/scripts/verify-managed-empty-stop.ts +28 -0
- package/src/async/job-manager.ts +228 -122
- package/src/capability/index.ts +18 -0
- package/src/capability/mcp.ts +2 -0
- package/src/capability/skill.ts +2 -0
- package/src/capability/types.ts +6 -0
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/config-cli.ts +8 -18
- package/src/cli/customize-doctor.ts +15 -2
- package/src/cli/public-command-errors.ts +21 -1
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/skills-cli.ts +5 -0
- package/src/cli-main.ts +7 -8
- package/src/commands/deep-interview.ts +47 -8
- package/src/commands/sdk.ts +140 -29
- package/src/config/autorouting-tier-map.ts +117 -7
- package/src/config/file-lock.ts +307 -68
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-bindings-applier.ts +20 -0
- package/src/config/model-profile-activation.ts +240 -46
- package/src/config/model-registry.ts +47 -153
- package/src/config/settings.ts +44 -4
- package/src/config/skill-settings-defaults.ts +7 -0
- package/src/coordinator-mcp/policy.ts +3 -2
- package/src/cursor-delete-path.ts +10 -0
- package/src/cursor-mcp-name.ts +15 -0
- package/src/cursor.ts +13 -2
- package/src/customization/inventory.ts +3 -0
- package/src/debug/report-bundle-parent.ts +22 -0
- package/src/debug/report-bundle.ts +3 -0
- package/src/debug/system-info.ts +13 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
- package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
- package/src/defaults/gjc-defaults.test.ts +18 -1
- package/src/defaults/gjc-defaults.ts +3 -0
- package/src/defaults/gjc-skills.generated.ts +58 -36
- package/src/discovery/agents.ts +6 -1
- package/src/discovery/builtin.ts +10 -0
- package/src/discovery/helpers.ts +168 -23
- package/src/discovery/mcp-json.ts +6 -0
- package/src/discovery/ssh.ts +9 -4
- package/src/discovery/substitute-plugin-root.ts +3 -1
- package/src/edit/file-read-cache.ts +1 -1
- package/src/eval/py/executor.ts +380 -120
- package/src/export/html/css-color.ts +9 -0
- package/src/export/html/index.ts +5 -4
- package/src/export/html/template.generated.ts +1 -1
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +7 -0
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +73 -8
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/plugins/marketplace/cache.ts +15 -0
- package/src/extensibility/plugins/marketplace/manager.ts +11 -3
- package/src/extensibility/plugins/plugin-link-path.ts +12 -0
- package/src/extensibility/runtime-skill-discovery.ts +20 -2
- package/src/extensibility/skill-management.ts +6 -2
- package/src/extensibility/skills.ts +6 -1
- package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
- package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
- package/src/gjc-runtime/deep-interview-stage.ts +98 -21
- package/src/gjc-runtime/gc-runtime.ts +206 -8
- package/src/gjc-runtime/launch-worktree.ts +14 -4
- package/src/gjc-runtime/ralplan-runtime.ts +447 -52
- package/src/gjc-runtime/state-argv.ts +2 -0
- package/src/gjc-runtime/state-migrations.ts +91 -29
- package/src/gjc-runtime/state-runtime.ts +3716 -135
- package/src/gjc-runtime/state-writer.ts +83 -8
- package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
- package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
- package/src/gjc-runtime/workflow-manifest.ts +54 -21
- package/src/harness-control-plane/operate.ts +12 -4
- package/src/harness-control-plane/owner.ts +5 -1
- package/src/hashline/parser.ts +48 -9
- package/src/hashline/recovery.ts +13 -4
- package/src/hindsight/config.ts +9 -3
- package/src/internal-urls/docs-index.generated.ts +19 -18
- package/src/internal-urls/skill-path.ts +19 -0
- package/src/internal-urls/skill-protocol.ts +2 -0
- package/src/lsp/edits.ts +6 -0
- package/src/lsp/workspace-path.ts +51 -0
- package/src/main.ts +195 -31
- package/src/modes/acp/acp-agent.ts +163 -7
- package/src/modes/components/custom-editor.ts +14 -0
- package/src/modes/components/customization/customization-dashboard.ts +12 -0
- package/src/modes/components/extensions/extension-dashboard.ts +2 -2
- package/src/modes/components/extensions/state-manager.ts +15 -5
- package/src/modes/components/model-selector.ts +1 -4
- package/src/modes/components/provider-onboarding-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +4 -0
- package/src/modes/controllers/event-controller.ts +11 -4
- package/src/modes/controllers/input-controller.ts +74 -29
- package/src/modes/controllers/runtime-mcp-command-controller.ts +8 -3
- package/src/modes/controllers/selector-controller.ts +28 -15
- package/src/modes/interactive-mode.ts +4 -0
- package/src/modes/runtime-init.ts +4 -0
- package/src/modes/utils/abort-message.ts +3 -1
- package/src/modes/utils/interrupt-ownership.ts +12 -0
- package/src/modes/utils/keybinding-matchers.ts +4 -0
- package/src/modes/utils/macos-option-forwarding.ts +80 -0
- package/src/progress/collect-project-progress.ts +153 -0
- package/src/progress/progress-contract.ts +172 -0
- package/src/progress/progress-snapshot.ts +140 -0
- package/src/progress/project-progress.ts +446 -0
- package/src/progress/render-progress.ts +209 -0
- package/src/prompts/system/master-mode.md +1 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/runtime-mcp/client.ts +13 -4
- package/src/runtime-mcp/config-writer.ts +10 -6
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/elicitation.ts +142 -0
- package/src/runtime-mcp/oauth-flow.ts +5 -0
- package/src/runtime-mcp/oauth-public-url.ts +8 -0
- package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
- package/src/runtime-mcp/smithery-registry.ts +22 -3
- package/src/runtime-mcp/transports/http.ts +2 -2
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk/acp/adapter.ts +93 -8
- package/src/sdk/broker/broker-exit.ts +52 -23
- package/src/sdk/broker/broker.ts +83 -7
- package/src/sdk/broker/ensure.ts +2 -0
- package/src/sdk/broker/lifecycle.ts +820 -73
- package/src/sdk/broker/session-index.ts +191 -81
- package/src/sdk/broker/task-artifact-owner-validation.ts +259 -0
- package/src/sdk/bus/chat-daemon-cli.ts +38 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +3 -0
- package/src/sdk/bus/index.ts +241 -46
- package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
- package/src/sdk/bus/telegram-daemon.ts +4 -2
- package/src/sdk/cli/session-cli.ts +17 -3
- package/src/sdk/client/client.ts +28 -8
- package/src/sdk/host/host.ts +6 -0
- package/src/sdk/host/query/handlers.ts +9 -1
- package/src/sdk/host/session-runtime.test.ts +2805 -411
- package/src/sdk/host/session-runtime.ts +428 -111
- package/src/sdk/host/surface-policy.ts +1 -0
- package/src/sdk/index.ts +8 -0
- package/src/sdk/lifecycle-session.ts +3 -1
- package/src/sdk/mcp/server.ts +15 -3
- package/src/sdk/prompt-deadline-manager.ts +15 -0
- package/src/sdk/protocol/operation-inventory.generated.json +146 -0
- package/src/sdk/protocol/operation-registry.ts +9 -2
- package/src/sdk/router/session-router.ts +94 -14
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +81 -38
- package/src/session/agent-session.ts +674 -224
- package/src/session/artifacts.ts +174 -70
- package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
- package/src/session/internal/managed-session-scope.ts +3457 -462
- package/src/session/internal/managed-session-storage.ts +482 -61
- package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
- package/src/session/internal/task-artifact-owner-access.ts +245 -0
- package/src/session/internal/task-artifact-owner-transcript.ts +614 -0
- package/src/session/session-manager.ts +939 -133
- package/src/session/session-retirement.ts +714 -0
- package/src/session/session-storage.ts +418 -174
- package/src/session/session-transcript-header.ts +17 -0
- package/src/session/task-artifact-owner-codec.ts +641 -0
- package/src/session/task-artifact-owner-retirement.ts +477 -0
- package/src/session/task-artifact-owner.ts +289 -0
- package/src/setup/credential-auto-import.ts +12 -3
- package/src/setup/credential-import.ts +176 -5
- package/src/setup/paseo/announce.ts +6 -1
- package/src/skill-state/active-state.ts +132 -2
- package/src/slash-commands/builtin-registry.ts +39 -9
- package/src/slash-commands/helpers/progress-report.ts +23 -0
- package/src/stt/setup.ts +3 -5
- package/src/task/commands.ts +3 -1
- package/src/task/executor.ts +4 -0
- package/src/task/index.ts +6 -0
- package/src/tools/ask.ts +205 -6
- package/src/tools/ast-edit.ts +4 -0
- package/src/tools/bash-allowed-prefixes.ts +15 -0
- package/src/tools/bash-skill-urls.ts +56 -3
- package/src/tools/bash.ts +48 -79
- package/src/tools/descriptors.ts +5 -1
- package/src/tools/eval.ts +56 -36
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +3 -0
- package/src/tools/python.ts +187 -66
- package/src/tools/recipe/index.ts +9 -0
- package/src/tools/recipe/recipe-guard.ts +19 -0
- package/src/tools/restricted-cwd.ts +10 -0
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +28 -1
- package/src/tools/todo-write.ts +10 -1
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/write.ts +1 -0
- package/src/utils/tools-checksum.ts +34 -0
- package/src/utils/tools-manager.ts +24 -6
- package/src/web/search/providers/codex.ts +3 -2
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
type AgentLoopConfig,
|
|
31
31
|
type AgentMessage,
|
|
32
32
|
type AgentState,
|
|
33
|
+
type AgentTerminalOwnerContext,
|
|
33
34
|
type AgentTool,
|
|
34
35
|
assertImagePlaceholdersHavePayload,
|
|
35
36
|
type ContextMaintenanceResult,
|
|
@@ -127,14 +128,15 @@ import {
|
|
|
127
128
|
streamSimple,
|
|
128
129
|
} from "@gajae-code/ai/core";
|
|
129
130
|
import { normalizeAnthropicBaseUrl } from "@gajae-code/ai/providers/anthropic";
|
|
131
|
+
import { isExplicitCodexTerminalVeto } from "@gajae-code/ai/providers/openai-codex-responses";
|
|
130
132
|
import {
|
|
131
133
|
type AuthDisposition,
|
|
132
134
|
beginAttempt,
|
|
133
135
|
classifyFallbackTrigger,
|
|
134
136
|
EMPTY_RESPONSE_PROVIDER_CODE,
|
|
135
137
|
type FallbackAttemptToken,
|
|
136
|
-
PROVIDER_PROTOCOL_MISMATCH_ERROR_CODE,
|
|
137
138
|
type FallbackTriggerClass,
|
|
139
|
+
PROVIDER_PROTOCOL_MISMATCH_ERROR_CODE,
|
|
138
140
|
SERVER_OVERLOADED_PROVIDER_CODE,
|
|
139
141
|
STREAM_FIRST_EVENT_TIMEOUT_PROVIDER_CODE,
|
|
140
142
|
} from "@gajae-code/ai/utils/fallback-transport";
|
|
@@ -217,6 +219,7 @@ import {
|
|
|
217
219
|
type FoldReason,
|
|
218
220
|
type JobFoldEvent,
|
|
219
221
|
type OwnerSubagentShutdownLease,
|
|
222
|
+
type SubagentLifecycle,
|
|
220
223
|
} from "../async";
|
|
221
224
|
import { reset as resetCapabilities } from "../capability";
|
|
222
225
|
import type { Rule } from "../capability/rule";
|
|
@@ -233,6 +236,15 @@ import {
|
|
|
233
236
|
UnknownModelProfileError,
|
|
234
237
|
validateModelProfileName,
|
|
235
238
|
} from "../config/model-profile-contract";
|
|
239
|
+
import {
|
|
240
|
+
commitDurableModelProfileOwnership,
|
|
241
|
+
type DurableModelProfileOwnership,
|
|
242
|
+
InvalidModelProfileOwnershipError,
|
|
243
|
+
ModelProfileOwnershipConflictError,
|
|
244
|
+
type ModelProfileOwnershipMarker,
|
|
245
|
+
modelProfileOwnershipMarkersEqual,
|
|
246
|
+
readDurableModelProfileOwnership,
|
|
247
|
+
} from "../config/model-profile-ownership";
|
|
236
248
|
import { resolveProfileBindings } from "../config/model-profiles";
|
|
237
249
|
import {
|
|
238
250
|
GJC_MODEL_ASSIGNMENT_TARGETS,
|
|
@@ -318,6 +330,7 @@ import {
|
|
|
318
330
|
buildSkillPromptMessage,
|
|
319
331
|
getSkillSlashCommandName,
|
|
320
332
|
isNamespacedSkillSlashCommandName,
|
|
333
|
+
type ParsedSkillInvocation,
|
|
321
334
|
parseSkillInvocations,
|
|
322
335
|
type Skill,
|
|
323
336
|
type SkillWarning,
|
|
@@ -407,11 +420,7 @@ import type { NotificationSessionController } from "../sdk/bus/session-control";
|
|
|
407
420
|
import { buildSyntheticModelId, syntheticNamespaceCollision } from "../sdk/model-profile-model";
|
|
408
421
|
import { sanitizePromptFailure } from "../sdk/prompt-failure";
|
|
409
422
|
import type { SecretObfuscator } from "../secrets/obfuscator";
|
|
410
|
-
import {
|
|
411
|
-
formatNoCredentialOnboardingError,
|
|
412
|
-
formatNoModelOnboardingError,
|
|
413
|
-
NoModelSelectedError,
|
|
414
|
-
} from "../setup/model-onboarding-guidance";
|
|
423
|
+
import { formatNoCredentialOnboardingError, NoModelSelectedError } from "../setup/model-onboarding-guidance";
|
|
415
424
|
import {
|
|
416
425
|
isCanonicalGjcWorkflowSkill,
|
|
417
426
|
isWorkflowContinuationInert,
|
|
@@ -526,6 +535,7 @@ import type {
|
|
|
526
535
|
SessionEntry,
|
|
527
536
|
SessionManagerCloseOutcome,
|
|
528
537
|
SessionMemoryStats,
|
|
538
|
+
SessionArtifactPublication,
|
|
529
539
|
} from "./session-manager";
|
|
530
540
|
import {
|
|
531
541
|
createReadonlySessionManager,
|
|
@@ -1217,6 +1227,11 @@ type SendUserMessageDispatchOptions = SendUserMessageOptions & {
|
|
|
1217
1227
|
};
|
|
1218
1228
|
|
|
1219
1229
|
type InternalPromptOptions = PromptOptions & { sdkRunToken?: string };
|
|
1230
|
+
interface SdkContinuationOwnership {
|
|
1231
|
+
scope: AttemptScope;
|
|
1232
|
+
token: string;
|
|
1233
|
+
cohort: string[];
|
|
1234
|
+
}
|
|
1220
1235
|
type InternalCustomMessageOptions = Pick<
|
|
1221
1236
|
PromptOptions,
|
|
1222
1237
|
| "streamingBehavior"
|
|
@@ -1426,6 +1441,7 @@ const PROVIDER_FIRST_EVENT_TIMEOUT_WITHOUT_ARTICLE_ERROR = "Provider stream time
|
|
|
1426
1441
|
const BARE_DEFAULT_CODEX_RETRYABLE_ERROR =
|
|
1427
1442
|
/^Codex error event(?:: .*)? \(code=(?:server_is_overloaded|server_error|internal_error)(?:, [^)]+)*\)$/;
|
|
1428
1443
|
const BARE_DEFAULT_CODEX_RETRYABLE_CODES = new Set(["server_is_overloaded", "server_error", "internal_error"]);
|
|
1444
|
+
const BARE_DEFAULT_CODEX_OVERLOAD_ERROR = /^Codex error event(?:: .*)? \(code=server_is_overloaded(?:, [^)]+)*\)$/;
|
|
1429
1445
|
const BARE_DEFAULT_OVERLOAD_CODES = new Set([SERVER_OVERLOADED_PROVIDER_CODE]);
|
|
1430
1446
|
/** Anthropic's typed capacity-overload `error.type`, the only Anthropic overload code admitted below. */
|
|
1431
1447
|
const ANTHROPIC_OVERLOADED_ERROR_TYPE = "overloaded_error";
|
|
@@ -1538,14 +1554,7 @@ function isExactTypedOverloadFacts(
|
|
|
1538
1554
|
facts.retryMaxAttempts === undefined
|
|
1539
1555
|
);
|
|
1540
1556
|
}
|
|
1541
|
-
|
|
1542
|
-
* True when transport facts are exactly the provider's statusless typed
|
|
1543
|
-
* capacity-overload code (the provider code verbatim and, when present, the
|
|
1544
|
-
* OpenAI code verbatim, with no status). The agent loop must not treat the new
|
|
1545
|
-
* facts as managed transaction authority, and managed session fallback must
|
|
1546
|
-
* not gain retry/advance authority from them, so this predicate keeps both
|
|
1547
|
-
* guards reading only typed facts, never error prose.
|
|
1548
|
-
*/
|
|
1557
|
+
|
|
1549
1558
|
function isStatuslessTypedOverloadFacts(facts: TransportFailureFacts | undefined): boolean {
|
|
1550
1559
|
if (!facts) return false;
|
|
1551
1560
|
return (
|
|
@@ -1554,10 +1563,38 @@ function isStatuslessTypedOverloadFacts(facts: TransportFailureFacts | undefined
|
|
|
1554
1563
|
(facts.openaiErrorCode === undefined || facts.openaiErrorCode === SERVER_OVERLOADED_PROVIDER_CODE)
|
|
1555
1564
|
);
|
|
1556
1565
|
}
|
|
1566
|
+
// Deterministic auth/request/model diagnostics must surface even when a provider
|
|
1567
|
+
// labels the failure with a transient code.
|
|
1568
|
+
const TERMINAL_ERROR_MESSAGE =
|
|
1569
|
+
/unauthorized|forbidden|authentication_error|permission_error|permission denied|invalid api key|invalid_request_error|invalid request|bad request|bad_request|validation_error|unprocessable|payload too large|payment required|insufficient_quota|insufficient credits|missing required (parameter|field)|invalid schema|invalid tool_choice|unsupported (parameter|value|model)|model_not_found|no such model|unknown model|does not (exist|support)|request was aborted|request aborted|the user aborted/i;
|
|
1570
|
+
|
|
1571
|
+
function isTerminalCodexProviderFailure(message: AssistantMessage): boolean {
|
|
1572
|
+
if (message.api !== "openai-codex-responses") return false;
|
|
1573
|
+
if (isExplicitCodexTerminalVeto(message.transportFailure?.providerCode, message.errorMessage)) return true;
|
|
1574
|
+
return (
|
|
1575
|
+
(BARE_DEFAULT_CODEX_RETRYABLE_CODES.has(message.transportFailure?.providerCode ?? "") ||
|
|
1576
|
+
BARE_DEFAULT_CODEX_RETRYABLE_ERROR.test(message.errorMessage ?? "")) &&
|
|
1577
|
+
TERMINAL_ERROR_MESSAGE.test(message.errorMessage ?? "")
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1557
1580
|
|
|
1558
1581
|
function isBareDefaultCodexOverload(message: AssistantMessage): boolean {
|
|
1559
1582
|
return (
|
|
1560
1583
|
message.api === "openai-codex-responses" &&
|
|
1584
|
+
!TERMINAL_ERROR_MESSAGE.test(message.errorMessage ?? "") &&
|
|
1585
|
+
!isExplicitCodexTerminalVeto(undefined, message.errorMessage) &&
|
|
1586
|
+
(isExactTypedOverloadFacts(message, BARE_DEFAULT_OVERLOAD_CODES) ||
|
|
1587
|
+
(BARE_DEFAULT_CODEX_OVERLOAD_ERROR.test(message.errorMessage ?? "") &&
|
|
1588
|
+
!hasBareDefaultRetryDisqualifyingFacts(message))) &&
|
|
1589
|
+
!assistantMessageHasVisibleOrToolContent(message)
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
function isBareDefaultCodexProviderFailure(message: AssistantMessage): boolean {
|
|
1594
|
+
return (
|
|
1595
|
+
message.api === "openai-codex-responses" &&
|
|
1596
|
+
!TERMINAL_ERROR_MESSAGE.test(message.errorMessage ?? "") &&
|
|
1597
|
+
!isExplicitCodexTerminalVeto(message.transportFailure?.providerCode, message.errorMessage) &&
|
|
1561
1598
|
(isExactTypedOverloadFacts(message, BARE_DEFAULT_CODEX_RETRYABLE_CODES) ||
|
|
1562
1599
|
(BARE_DEFAULT_CODEX_RETRYABLE_ERROR.test(message.errorMessage ?? "") &&
|
|
1563
1600
|
!hasBareDefaultRetryDisqualifyingFacts(message))) &&
|
|
@@ -1620,7 +1657,10 @@ function isBareDefaultAnthropicOverload(message: AssistantMessage): boolean {
|
|
|
1620
1657
|
function assistantMessageHasVisibleOrToolContent(message: AssistantMessage): boolean {
|
|
1621
1658
|
return message.content.some(content => {
|
|
1622
1659
|
if (content.type === "text") return content.text.length > 0;
|
|
1623
|
-
|
|
1660
|
+
if (content.type === "thinking") {
|
|
1661
|
+
return content.thinking.length > 0 || (content.thinkingSignature?.length ?? 0) > 0;
|
|
1662
|
+
}
|
|
1663
|
+
return content.type === "redactedThinking" || content.type === "toolCall";
|
|
1624
1664
|
});
|
|
1625
1665
|
}
|
|
1626
1666
|
|
|
@@ -1763,20 +1803,14 @@ function summarizeAgentBashArtifactSave(
|
|
|
1763
1803
|
};
|
|
1764
1804
|
}
|
|
1765
1805
|
|
|
1766
|
-
export interface AgentBashArtifactStore {
|
|
1767
|
-
saveArtifact(content: string, toolType: string): Promise<string | undefined>;
|
|
1768
|
-
getArtifactPath(id: string): Promise<string | null>;
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
1806
|
export async function saveAgentBashOriginalArtifact(
|
|
1772
|
-
|
|
1807
|
+
publication: SessionArtifactPublication,
|
|
1773
1808
|
originalText: string,
|
|
1774
1809
|
): Promise<BashArtifactSaveResult> {
|
|
1775
1810
|
try {
|
|
1776
|
-
const artifactId = await
|
|
1777
|
-
if (!artifactId) return { status: "
|
|
1778
|
-
|
|
1779
|
-
return artifactPath ? summarizeAgentBashArtifactSave(artifactId, originalText) : { status: "unavailable" };
|
|
1811
|
+
const artifactId = await publication(originalText, "bash-original");
|
|
1812
|
+
if (!artifactId) return { status: "unavailable" };
|
|
1813
|
+
return summarizeAgentBashArtifactSave(artifactId, originalText);
|
|
1780
1814
|
} catch (error) {
|
|
1781
1815
|
return { status: "failed", diagnostic: boundAgentBashArtifactSaveDiagnostic(error) };
|
|
1782
1816
|
}
|
|
@@ -2729,6 +2763,7 @@ export class AgentSession {
|
|
|
2729
2763
|
#scopedModels: ScopedModelSelection[];
|
|
2730
2764
|
#thinkingLevel: ThinkingLevel | undefined;
|
|
2731
2765
|
#activeModelProfile: string | undefined;
|
|
2766
|
+
#unavailableModelProfile: string | undefined;
|
|
2732
2767
|
#activeProfileInstalledRoles = new Map<string, ModelSelectorValue | undefined>();
|
|
2733
2768
|
#activeProfileInstalledAgentOverrides = new Map<string, ModelSelectorValue | undefined>();
|
|
2734
2769
|
#preProfileModel: Model | undefined;
|
|
@@ -2754,6 +2789,9 @@ export class AgentSession {
|
|
|
2754
2789
|
#followUpReservationTransitionWaiters = new Set<() => void>();
|
|
2755
2790
|
#selectionFenceGeneration = 0;
|
|
2756
2791
|
#defaultModelSelectionMutationRevision = 0;
|
|
2792
|
+
#userModelSelectionRevision = 0;
|
|
2793
|
+
#userCanonicalVariantSelectionRevision = 0;
|
|
2794
|
+
#userCanonicalVariantSelection: string | undefined;
|
|
2757
2795
|
#thinkingLevelMutationRevision = 0;
|
|
2758
2796
|
#thinkingVisibilityMutationRevision = 0;
|
|
2759
2797
|
#thinkingLevelLiveMutationRevision = 0;
|
|
@@ -3404,8 +3442,17 @@ export class AgentSession {
|
|
|
3404
3442
|
this.#activeAttemptScope = undefined;
|
|
3405
3443
|
this.#activeLogicalRunId = undefined;
|
|
3406
3444
|
}
|
|
3407
|
-
#
|
|
3408
|
-
const
|
|
3445
|
+
#captureSdkContinuationOwnership(scope: AttemptScope | undefined): SdkContinuationOwnership | undefined {
|
|
3446
|
+
const token = scope ? this.#sdkRunTokensByAttemptScope.get(scope) : undefined;
|
|
3447
|
+
if (!scope || token === undefined) return undefined;
|
|
3448
|
+
return { scope, token, cohort: [...(this.#sdkRunCohortsByAttemptScope.get(scope) ?? [token])] };
|
|
3449
|
+
}
|
|
3450
|
+
#acceptSdkAttemptRun(
|
|
3451
|
+
handle: AttemptRunHandle,
|
|
3452
|
+
sdkRunToken?: string,
|
|
3453
|
+
sdkRunTokens?: string[],
|
|
3454
|
+
predecessorScope?: AttemptScope,
|
|
3455
|
+
): void {
|
|
3409
3456
|
const predecessorSdkRunToken =
|
|
3410
3457
|
predecessorScope === undefined ? undefined : this.#sdkRunTokensByAttemptScope.get(predecessorScope);
|
|
3411
3458
|
const carryRecoverySkip =
|
|
@@ -3415,14 +3462,23 @@ export class AgentSession {
|
|
|
3415
3462
|
this.#skipPostPromptRecoveryWaitByAttemptScope.delete(predecessorScope);
|
|
3416
3463
|
this.#acceptRunHandle(handle);
|
|
3417
3464
|
this.#settleTrackedOwnRunPromotions(handle);
|
|
3465
|
+
// Logical continuation lineage is causal even without an SDK submission.
|
|
3466
|
+
if (predecessorScope) {
|
|
3467
|
+
this.#lifecycleScopesByAttemptScope.set(
|
|
3468
|
+
handle.scope,
|
|
3469
|
+
this.#lifecycleScopesByAttemptScope.get(predecessorScope) ?? predecessorScope,
|
|
3470
|
+
);
|
|
3471
|
+
}
|
|
3418
3472
|
if (sdkRunToken !== undefined) {
|
|
3419
3473
|
this.#activeSdkRunToken = sdkRunToken;
|
|
3420
3474
|
this.#sdkRunTokensByAttemptScope.set(handle.scope, sdkRunToken);
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3475
|
+
this.#sdkRunCohortsByAttemptScope.set(handle.scope, sdkRunTokens ?? [sdkRunToken]);
|
|
3476
|
+
for (const token of this.#sdkRunCohortsByAttemptScope.get(handle.scope) ?? []) {
|
|
3477
|
+
if (this.#sdkTerminalPublications.has(token)) continue;
|
|
3478
|
+
const publication = Promise.withResolvers<void>();
|
|
3479
|
+
void publication.promise.catch(() => undefined);
|
|
3480
|
+
this.#sdkTerminalPublications.set(token, publication);
|
|
3481
|
+
}
|
|
3426
3482
|
}
|
|
3427
3483
|
if (carryRecoverySkip) this.#skipPostPromptRecoveryWaitByAttemptScope.add(handle.scope);
|
|
3428
3484
|
}
|
|
@@ -3572,6 +3628,7 @@ export class AgentSession {
|
|
|
3572
3628
|
#restoreManagedFallbackGetApiKey: (() => void) | undefined;
|
|
3573
3629
|
// Todo completion reminder state
|
|
3574
3630
|
#todoReminderCount = 0;
|
|
3631
|
+
#todoReminderContinuationGeneration: number | undefined;
|
|
3575
3632
|
#deepInterviewUserIntentEpoch = 0;
|
|
3576
3633
|
#deepInterviewTurnOwnerEpoch = 0;
|
|
3577
3634
|
#deepInterviewGenuineUserMessageEpochs = new WeakMap<object, number>();
|
|
@@ -3765,6 +3822,7 @@ export class AgentSession {
|
|
|
3765
3822
|
#skipPostPromptRecoveryWaitByAttemptScope = new WeakSet<AttemptScope>();
|
|
3766
3823
|
#sdkRunTokensByAttemptScope = new WeakMap<AttemptScope, string>();
|
|
3767
3824
|
#sdkRunCohortsByAttemptScope = new WeakMap<AttemptScope, string[]>();
|
|
3825
|
+
#lifecycleScopesByAttemptScope = new WeakMap<AttemptScope, AttemptScope>();
|
|
3768
3826
|
#activeSdkRunToken: string | undefined;
|
|
3769
3827
|
#activeAttemptScope: AttemptScope | undefined;
|
|
3770
3828
|
#attemptAuthority!: AttemptScopeAuthority;
|
|
@@ -3990,6 +4048,8 @@ export class AgentSession {
|
|
|
3990
4048
|
// async event handlers settle. Subscribers treat agent_end as readiness, so
|
|
3991
4049
|
// publishing it earlier lets a successor corrupt the prior prompt's lifecycle.
|
|
3992
4050
|
#pendingAgentEndEmit: AgentSessionEvent | undefined;
|
|
4051
|
+
#agentEndContinuationDecisions = new WeakSet<AgentSessionEvent>();
|
|
4052
|
+
#pendingSdkAgentEnds = new Set<AgentSessionEvent>();
|
|
3993
4053
|
// A scheduled continuation owns this terminal boundary until it either starts
|
|
3994
4054
|
// the successor or proves it cannot. Holds prevent a false idle event while
|
|
3995
4055
|
// preserving the predecessor for cancellation and preflight failures.
|
|
@@ -4000,6 +4060,8 @@ export class AgentSession {
|
|
|
4000
4060
|
#agentEndPublicationInFlight = 0;
|
|
4001
4061
|
#agentEndPublicationPromise: Promise<void> = Promise.resolve();
|
|
4002
4062
|
#agentEndHandlingPromise: Promise<void> = Promise.resolve();
|
|
4063
|
+
#sdkTerminalPublications = new Map<string, PromiseWithResolvers<void>>();
|
|
4064
|
+
#publishingSdkTerminals = new Set<PromiseWithResolvers<void>>();
|
|
4003
4065
|
|
|
4004
4066
|
#obfuscator: SecretObfuscator | undefined;
|
|
4005
4067
|
#checkpointState: CheckpointState | undefined = undefined;
|
|
@@ -4038,11 +4100,7 @@ export class AgentSession {
|
|
|
4038
4100
|
readonly rawSseDebugBuffer: RawSseDebugBuffer;
|
|
4039
4101
|
|
|
4040
4102
|
#acquirePowerAssertion(): void {
|
|
4041
|
-
if (
|
|
4042
|
-
process.platform !== "darwin" &&
|
|
4043
|
-
process.platform !== "linux" &&
|
|
4044
|
-
process.platform !== "win32"
|
|
4045
|
-
) {
|
|
4103
|
+
if (process.platform !== "darwin" && process.platform !== "linux" && process.platform !== "win32") {
|
|
4046
4104
|
return;
|
|
4047
4105
|
}
|
|
4048
4106
|
if (this.#powerAssertion || this.#powerAssertionLoad) return;
|
|
@@ -4672,8 +4730,21 @@ export class AgentSession {
|
|
|
4672
4730
|
}
|
|
4673
4731
|
}
|
|
4674
4732
|
|
|
4675
|
-
#reserveDeferredAgentEndForContinuation(): symbol | undefined {
|
|
4676
|
-
const
|
|
4733
|
+
#reserveDeferredAgentEndForContinuation(predecessorScope?: AttemptScope): symbol | undefined {
|
|
4734
|
+
const resourceRunId = this.#runResourceLeaseContext.getStore()?.resourceRunId;
|
|
4735
|
+
const pending = predecessorScope
|
|
4736
|
+
? [...this.#pendingSdkAgentEnds].find(
|
|
4737
|
+
event => (event as AgentSessionEvent & { scope?: AttemptScope }).scope === predecessorScope,
|
|
4738
|
+
)
|
|
4739
|
+
: resourceRunId === undefined
|
|
4740
|
+
? this.#pendingAgentEndEmit
|
|
4741
|
+
: ([...this.#pendingSdkAgentEnds].find(
|
|
4742
|
+
event => getAgentTerminalOwnerContext(event)?.resourceRunId === resourceRunId,
|
|
4743
|
+
) ??
|
|
4744
|
+
(this.#pendingAgentEndEmit &&
|
|
4745
|
+
getAgentTerminalOwnerContext(this.#pendingAgentEndEmit)?.resourceRunId === resourceRunId
|
|
4746
|
+
? this.#pendingAgentEndEmit
|
|
4747
|
+
: undefined));
|
|
4677
4748
|
if (!pending) return undefined;
|
|
4678
4749
|
const hold = Symbol("deferred-agent-end-continuation");
|
|
4679
4750
|
this.#pendingAgentEndContinuationHolds.set(hold, pending);
|
|
@@ -4687,6 +4758,8 @@ export class AgentSession {
|
|
|
4687
4758
|
throw new Error("Cannot restore a deferred agent_end over a different pending terminal event");
|
|
4688
4759
|
}
|
|
4689
4760
|
this.#pendingAgentEndEmit = pending;
|
|
4761
|
+
const scope = (pending as AgentSessionEvent & { scope?: AttemptScope }).scope;
|
|
4762
|
+
if (scope && this.#sdkRunTokensByAttemptScope.has(scope)) this.#pendingSdkAgentEnds.add(pending);
|
|
4690
4763
|
const hold = Symbol("deferred-agent-end-continuation");
|
|
4691
4764
|
this.#pendingAgentEndContinuationHolds.set(hold, pending);
|
|
4692
4765
|
this.#deferredAgentEndWorkLeases.set(hold, this.#sessionWorkLease.acquire());
|
|
@@ -4697,6 +4770,7 @@ export class AgentSession {
|
|
|
4697
4770
|
if (!hold) return undefined;
|
|
4698
4771
|
const pending = this.#pendingAgentEndContinuationHolds.get(hold);
|
|
4699
4772
|
this.#pendingAgentEndContinuationHolds.delete(hold);
|
|
4773
|
+
if (pending) this.#pendingSdkAgentEnds.delete(pending);
|
|
4700
4774
|
this.#deferredAgentEndWorkLeases.get(hold)?.release();
|
|
4701
4775
|
this.#deferredAgentEndWorkLeases.delete(hold);
|
|
4702
4776
|
if (pending && this.#pendingAgentEndEmit === pending) {
|
|
@@ -4714,6 +4788,8 @@ export class AgentSession {
|
|
|
4714
4788
|
}
|
|
4715
4789
|
|
|
4716
4790
|
#restoreDeferredAgentEndAfterContinuationFailure(pending: AgentSessionEvent | undefined): void {
|
|
4791
|
+
const scope = (pending as (AgentSessionEvent & { scope?: AttemptScope }) | undefined)?.scope;
|
|
4792
|
+
if (pending && scope && this.#sdkRunTokensByAttemptScope.has(scope)) this.#pendingSdkAgentEnds.add(pending);
|
|
4717
4793
|
if (pending && !this.#pendingAgentEndEmit) {
|
|
4718
4794
|
this.#pendingAgentEndEmit = pending;
|
|
4719
4795
|
}
|
|
@@ -4726,6 +4802,8 @@ export class AgentSession {
|
|
|
4726
4802
|
): void {
|
|
4727
4803
|
if (!hold || !pending) return;
|
|
4728
4804
|
this.#pendingAgentEndEmit = pending;
|
|
4805
|
+
const scope = (pending as AgentSessionEvent & { scope?: AttemptScope }).scope;
|
|
4806
|
+
if (scope && this.#sdkRunTokensByAttemptScope.has(scope)) this.#pendingSdkAgentEnds.add(pending);
|
|
4729
4807
|
this.#pendingAgentEndContinuationHolds.set(hold, pending);
|
|
4730
4808
|
}
|
|
4731
4809
|
|
|
@@ -5028,11 +5106,15 @@ export class AgentSession {
|
|
|
5028
5106
|
this.#flushPendingAgentEnd();
|
|
5029
5107
|
return flushError;
|
|
5030
5108
|
}
|
|
5031
|
-
async #settleEndedInFlight(
|
|
5109
|
+
async #settleEndedInFlight(
|
|
5110
|
+
token: symbol,
|
|
5111
|
+
promptWait?: "publication" | "full",
|
|
5112
|
+
sdkPublication?: Promise<void>,
|
|
5113
|
+
): Promise<void> {
|
|
5032
5114
|
const flushError = this.#endInFlight(token);
|
|
5033
5115
|
const predecessorPromptStillInFlight = this.#livePromptsInFlight() > 0;
|
|
5034
5116
|
if (promptWait === "publication") {
|
|
5035
|
-
await this.#agentEndPublicationPromise;
|
|
5117
|
+
await (sdkPublication ?? this.#agentEndPublicationPromise);
|
|
5036
5118
|
} else if (promptWait === "full") {
|
|
5037
5119
|
await this.#agentEndHandlingPromise;
|
|
5038
5120
|
await this.#waitForPostPromptRecovery();
|
|
@@ -5072,13 +5154,23 @@ export class AgentSession {
|
|
|
5072
5154
|
}
|
|
5073
5155
|
|
|
5074
5156
|
#flushPendingAgentEnd(): void {
|
|
5157
|
+
for (const sdkPending of this.#pendingSdkAgentEnds) {
|
|
5158
|
+
if (!this.#agentEndContinuationDecisions.has(sdkPending)) continue;
|
|
5159
|
+
if ([...this.#pendingAgentEndContinuationHolds.values()].includes(sdkPending)) continue;
|
|
5160
|
+
this.#pendingSdkAgentEnds.delete(sdkPending);
|
|
5161
|
+
if (this.#pendingAgentEndEmit === sdkPending) this.#pendingAgentEndEmit = undefined;
|
|
5162
|
+
const sdkLease = this.#deferredAgentEndLeases.get(sdkPending);
|
|
5163
|
+
this.#deferredAgentEndLeases.delete(sdkPending);
|
|
5164
|
+
this.#startAgentEndPublication(sdkPending, sdkLease);
|
|
5165
|
+
}
|
|
5166
|
+
const pending = this.#pendingAgentEndEmit;
|
|
5167
|
+
if (pending && this.#pendingSdkAgentEnds.has(pending)) return;
|
|
5075
5168
|
if (
|
|
5076
5169
|
this.#livePromptsInFlight() > 0 ||
|
|
5077
5170
|
this.#agentEventHandlersInFlight > 0 ||
|
|
5078
5171
|
this.#pendingAgentEndContinuationHolds.size > 0
|
|
5079
5172
|
)
|
|
5080
5173
|
return;
|
|
5081
|
-
const pending = this.#pendingAgentEndEmit;
|
|
5082
5174
|
if (!pending) {
|
|
5083
5175
|
this.#resolveSessionSettlement();
|
|
5084
5176
|
return;
|
|
@@ -5090,13 +5182,16 @@ export class AgentSession {
|
|
|
5090
5182
|
}
|
|
5091
5183
|
|
|
5092
5184
|
#startAgentEndPublication(pending: AgentSessionEvent, lease?: RunResourceProducerLease): void {
|
|
5185
|
+
this.#agentEndContinuationDecisions.delete(pending);
|
|
5093
5186
|
this.#agentEndPublicationInFlight++;
|
|
5094
5187
|
const pendingScope = (pending as AgentSessionEvent & { scope?: AttemptScopeRef }).scope as
|
|
5095
5188
|
| AttemptScope
|
|
5096
5189
|
| undefined;
|
|
5097
5190
|
const sdkTerminal = pendingScope !== undefined && this.#sdkRunTokensByAttemptScope.has(pendingScope);
|
|
5098
5191
|
this.#agentEndPublicationPromise = this.#publishDeferredAgentEnd(pending, lease, sdkTerminal);
|
|
5099
|
-
void this.#agentEndPublicationPromise
|
|
5192
|
+
void this.#agentEndPublicationPromise.catch(error => {
|
|
5193
|
+
logger.warn("Agent terminal publication failed", { error: sanitizePromptFailure(error) });
|
|
5194
|
+
});
|
|
5100
5195
|
}
|
|
5101
5196
|
|
|
5102
5197
|
async #publishDeferredAgentEnd(
|
|
@@ -5112,6 +5207,13 @@ export class AgentSession {
|
|
|
5112
5207
|
const publicationCorrelationId = publicationScope
|
|
5113
5208
|
? this.#sdkRunTokensByAttemptScope.get(publicationScope)
|
|
5114
5209
|
: undefined;
|
|
5210
|
+
const sdkPublications = (publicationScope ? (this.#sdkRunCohortsByAttemptScope.get(publicationScope) ?? []) : [])
|
|
5211
|
+
.map(token => ({ token, publication: this.#sdkTerminalPublications.get(token) }))
|
|
5212
|
+
.filter(
|
|
5213
|
+
(entry): entry is { token: string; publication: PromiseWithResolvers<void> } =>
|
|
5214
|
+
entry.publication !== undefined,
|
|
5215
|
+
);
|
|
5216
|
+
for (const { publication } of sdkPublications) this.#publishingSdkTerminals.add(publication);
|
|
5115
5217
|
let extensionDelivery: Promise<void> | undefined;
|
|
5116
5218
|
const releaseLease = () => {
|
|
5117
5219
|
if (!lease) return;
|
|
@@ -5204,7 +5306,15 @@ export class AgentSession {
|
|
|
5204
5306
|
try {
|
|
5205
5307
|
if (lease) await this.#runResourceLeaseContext.run(lease, publish);
|
|
5206
5308
|
else await publish();
|
|
5309
|
+
for (const { publication } of sdkPublications) publication.resolve();
|
|
5310
|
+
} catch (error) {
|
|
5311
|
+
for (const { publication } of sdkPublications) publication.reject(error);
|
|
5312
|
+
throw error;
|
|
5207
5313
|
} finally {
|
|
5314
|
+
for (const { token, publication } of sdkPublications) {
|
|
5315
|
+
this.#publishingSdkTerminals.delete(publication);
|
|
5316
|
+
if (this.#sdkTerminalPublications.get(token) === publication) this.#sdkTerminalPublications.delete(token);
|
|
5317
|
+
}
|
|
5208
5318
|
if (extensionDelivery) void extensionDelivery.then(releaseLease, releaseLease);
|
|
5209
5319
|
else releaseLease();
|
|
5210
5320
|
this.#agentEndPublicationInFlight = Math.max(0, this.#agentEndPublicationInFlight - 1);
|
|
@@ -5463,12 +5573,7 @@ export class AgentSession {
|
|
|
5463
5573
|
controller !== undefined &&
|
|
5464
5574
|
controller.chain.entries.length > 1;
|
|
5465
5575
|
if (shouldCapture && modelKey) this.#managedFallbackActiveCredentialRows.delete(modelKey);
|
|
5466
|
-
if (
|
|
5467
|
-
override &&
|
|
5468
|
-
model &&
|
|
5469
|
-
storageProvider === override.storageProvider &&
|
|
5470
|
-
modelKey === override.modelKey
|
|
5471
|
-
) {
|
|
5576
|
+
if (override && model && storageProvider === override.storageProvider && modelKey === override.modelKey) {
|
|
5472
5577
|
this.#managedFallbackNextCredentialOverride = undefined;
|
|
5473
5578
|
const apiKey = await this.#modelRegistry.getApiKey(model, this.credentialSessionId, {
|
|
5474
5579
|
credentialSelector: { kind: "id", value: String(override.rowId) },
|
|
@@ -5478,10 +5583,7 @@ export class AgentSession {
|
|
|
5478
5583
|
return apiKey;
|
|
5479
5584
|
}
|
|
5480
5585
|
// The preselected credential is no longer available; try to resolve another one of the same kind.
|
|
5481
|
-
const fallbackApiKey = await this.#resolveManagedFallbackCredentialRow(
|
|
5482
|
-
model,
|
|
5483
|
-
override.credentialKind,
|
|
5484
|
-
);
|
|
5586
|
+
const fallbackApiKey = await this.#resolveManagedFallbackCredentialRow(model, override.credentialKind);
|
|
5485
5587
|
if (fallbackApiKey !== undefined) {
|
|
5486
5588
|
if (shouldCapture && model) this.#captureManagedFallbackActiveCredential(model);
|
|
5487
5589
|
return fallbackApiKey;
|
|
@@ -5489,8 +5591,7 @@ export class AgentSession {
|
|
|
5489
5591
|
throw new Error("Selected managed fallback credential is no longer available");
|
|
5490
5592
|
}
|
|
5491
5593
|
const apiKey = await invokeOriginalGetApiKey(provider);
|
|
5492
|
-
if (shouldCapture && model && isAuthenticated(apiKey))
|
|
5493
|
-
this.#captureManagedFallbackActiveCredential(model);
|
|
5594
|
+
if (shouldCapture && model && isAuthenticated(apiKey)) this.#captureManagedFallbackActiveCredential(model);
|
|
5494
5595
|
return apiKey;
|
|
5495
5596
|
};
|
|
5496
5597
|
this.agent.getApiKey = managedGetApiKey;
|
|
@@ -5577,12 +5678,14 @@ export class AgentSession {
|
|
|
5577
5678
|
void this.#queueFollowUpAfterReservation(message, displayText, {
|
|
5578
5679
|
createDisplayEntry: false,
|
|
5579
5680
|
trackExternalFollowUp: false,
|
|
5681
|
+
sdkRunToken: this.#activeSdkRunToken,
|
|
5580
5682
|
}).catch(error => {
|
|
5581
5683
|
this.#settleDeliveredOwnedRegistrations([message]);
|
|
5582
5684
|
logger.warn("Owned streaming follow-up was rejected", { error: String(error) });
|
|
5583
5685
|
});
|
|
5584
5686
|
},
|
|
5585
5687
|
injectIdle: async (messages, signal) => {
|
|
5688
|
+
const sdkRunToken = this.#activeSdkRunToken;
|
|
5586
5689
|
// Mandated boundary comment (corrected turn semantics): same origin
|
|
5587
5690
|
// split as the streaming injector — an allowed owned-completion
|
|
5588
5691
|
// delivery starts a fresh turn attempt/lineage and is not a
|
|
@@ -5617,14 +5720,14 @@ export class AgentSession {
|
|
|
5617
5720
|
await this.agent.prompt(first, {
|
|
5618
5721
|
...this.#managedFallbackPromptOptions(),
|
|
5619
5722
|
onRunAccepted: (handle: AttemptRunHandle) => {
|
|
5620
|
-
if (handle) this.#acceptSdkAttemptRun(handle);
|
|
5723
|
+
if (handle) this.#acceptSdkAttemptRun(handle, sdkRunToken);
|
|
5621
5724
|
},
|
|
5622
5725
|
});
|
|
5623
5726
|
} else {
|
|
5624
5727
|
await this.agent.prompt(survivors, {
|
|
5625
5728
|
...this.#managedFallbackPromptOptions(),
|
|
5626
5729
|
onRunAccepted: (handle: AttemptRunHandle) => {
|
|
5627
|
-
if (handle) this.#acceptSdkAttemptRun(handle);
|
|
5730
|
+
if (handle) this.#acceptSdkAttemptRun(handle, sdkRunToken);
|
|
5628
5731
|
},
|
|
5629
5732
|
});
|
|
5630
5733
|
}
|
|
@@ -5796,9 +5899,8 @@ export class AgentSession {
|
|
|
5796
5899
|
(largestPhase, phase) =>
|
|
5797
5900
|
Math.max(
|
|
5798
5901
|
largestPhase,
|
|
5799
|
-
phase.tasks.filter(
|
|
5800
|
-
|
|
5801
|
-
).length,
|
|
5902
|
+
phase.tasks.filter(task => task.status === "pending" || task.status === "in_progress")
|
|
5903
|
+
.length,
|
|
5802
5904
|
),
|
|
5803
5905
|
0,
|
|
5804
5906
|
);
|
|
@@ -6712,6 +6814,17 @@ export class AgentSession {
|
|
|
6712
6814
|
return { running, recent, delivery };
|
|
6713
6815
|
}
|
|
6714
6816
|
|
|
6817
|
+
/**
|
|
6818
|
+
* Lifecycle status of every subagent owned by this session, read from the
|
|
6819
|
+
* manager's stable control-plane records (they outlive AsyncJob eviction).
|
|
6820
|
+
*/
|
|
6821
|
+
getSubagentLifecycleStatuses(): SubagentLifecycle[] {
|
|
6822
|
+
const manager = this.#ownedAsyncJobManager ?? AsyncJobManager.instance();
|
|
6823
|
+
if (!manager) return [];
|
|
6824
|
+
const ownerFilter = this.#agentId ? { ownerId: this.#agentId } : undefined;
|
|
6825
|
+
return manager.getSubagentRecords(ownerFilter).map(record => record.status);
|
|
6826
|
+
}
|
|
6827
|
+
|
|
6715
6828
|
/**
|
|
6716
6829
|
* Cancel async jobs registered by *this* agent only. Used by lifecycle
|
|
6717
6830
|
* transitions (newSession, switchSession, handoff, dispose) so a subagent
|
|
@@ -6887,6 +7000,8 @@ export class AgentSession {
|
|
|
6887
7000
|
object,
|
|
6888
7001
|
{ scope?: AttemptScope; sdkRunToken?: string; persistGeneration: number; persistBarrier?: Promise<void> }
|
|
6889
7002
|
>();
|
|
7003
|
+
/** Extension handlers cannot mutate or replace the Agent-claimed run owner. */
|
|
7004
|
+
#terminalOwnerByExtensionEvent = new WeakMap<object, AgentTerminalOwnerContext>();
|
|
6890
7005
|
|
|
6891
7006
|
/**
|
|
6892
7007
|
* Capture what is true at the SYNCHRONOUS agent-event boundary, before any async work.
|
|
@@ -7040,8 +7155,8 @@ export class AgentSession {
|
|
|
7040
7155
|
const pendingAgentEnd =
|
|
7041
7156
|
event.type === "agent_end" &&
|
|
7042
7157
|
!maintenanceCheckpoint &&
|
|
7043
|
-
(this.#pendingAgentEndEmit === event || this.#
|
|
7044
|
-
?
|
|
7158
|
+
(this.#pendingAgentEndEmit === event || this.#pendingSdkAgentEnds.has(event))
|
|
7159
|
+
? event
|
|
7045
7160
|
: undefined;
|
|
7046
7161
|
if (pendingAgentEnd) {
|
|
7047
7162
|
this.#deferredAgentEndLeases.set(pendingAgentEnd, eventLease);
|
|
@@ -7058,6 +7173,7 @@ export class AgentSession {
|
|
|
7058
7173
|
}
|
|
7059
7174
|
}
|
|
7060
7175
|
this.#agentEventHandlersInFlight = Math.max(0, this.#agentEventHandlersInFlight - 1);
|
|
7176
|
+
if (event.type === "agent_end") this.#agentEndContinuationDecisions.add(event);
|
|
7061
7177
|
this.#flushPendingAgentEnd();
|
|
7062
7178
|
agentEndHandled?.resolve();
|
|
7063
7179
|
// Every other in-flight counter republishes settlement when it drops; this
|
|
@@ -7294,16 +7410,10 @@ export class AgentSession {
|
|
|
7294
7410
|
// have unwound. Subscribers treat this event as the ready signal; flushing it
|
|
7295
7411
|
// from abort while either barrier is active permits a successor to race the
|
|
7296
7412
|
// prior prompt's cleanup.
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
if (
|
|
7300
|
-
event.type === "agent_end" &&
|
|
7301
|
-
sdkTerminal &&
|
|
7302
|
-
this.#pendingAgentEndContinuationHolds.size === 0 &&
|
|
7303
|
-
this.#pendingAgentEndEmit === undefined
|
|
7304
|
-
) {
|
|
7413
|
+
if (event.type === "agent_end" && attemptScope && this.#sdkRunTokensByAttemptScope.has(attemptScope)) {
|
|
7414
|
+
this.#pendingSdkAgentEnds.add(event);
|
|
7305
7415
|
if (eventLease) this.#deferredAgentEndLeases.set(event, eventLease);
|
|
7306
|
-
this.#
|
|
7416
|
+
this.#pendingAgentEndEmit = event;
|
|
7307
7417
|
return;
|
|
7308
7418
|
}
|
|
7309
7419
|
if (event.type === "agent_end" && (this.#livePromptsInFlight() > 0 || this.#agentEventHandlersInFlight > 0)) {
|
|
@@ -7417,6 +7527,8 @@ export class AgentSession {
|
|
|
7417
7527
|
eventLease?: RunResourceProducerLease,
|
|
7418
7528
|
): Promise<void> => {
|
|
7419
7529
|
const attemptScope = (event as AgentEvent & { scope?: AttemptScope }).scope;
|
|
7530
|
+
const terminalSdkOwnership =
|
|
7531
|
+
event.type === "agent_end" ? this.#captureSdkContinuationOwnership(attemptScope) : undefined;
|
|
7420
7532
|
|
|
7421
7533
|
// These lifecycle boundaries can be delivered without awaiting this listener.
|
|
7422
7534
|
// Revoke streaming-edit cache generations before any admission, spill, or
|
|
@@ -8125,7 +8237,7 @@ export class AgentSession {
|
|
|
8125
8237
|
skipCompactionCheck: true,
|
|
8126
8238
|
resourceRunId: activePromptHandle,
|
|
8127
8239
|
maintenanceContinuation: true,
|
|
8128
|
-
|
|
8240
|
+
sdkOwnership: terminalSdkOwnership,
|
|
8129
8241
|
});
|
|
8130
8242
|
}
|
|
8131
8243
|
return;
|
|
@@ -8209,7 +8321,9 @@ export class AgentSession {
|
|
|
8209
8321
|
}
|
|
8210
8322
|
|
|
8211
8323
|
// Check for retryable errors first (overloaded, rate limit, server errors)
|
|
8212
|
-
|
|
8324
|
+
// Skip retry for todo reminder continuations - they should fail silently without retrying
|
|
8325
|
+
const isReminderContinuationError = this.#todoReminderContinuationGeneration === agentEndGeneration && agentEndGeneration !== undefined;
|
|
8326
|
+
if (!isReminderContinuationError && this.#isRetryableError(msg)) {
|
|
8213
8327
|
const transportFailure = (msg as AssistantMessage & { transportFailure?: TransportFailureFacts })
|
|
8214
8328
|
.transportFailure;
|
|
8215
8329
|
const messageScope = this.#assistantAttemptScopes.get(msg);
|
|
@@ -8222,6 +8336,10 @@ export class AgentSession {
|
|
|
8222
8336
|
);
|
|
8223
8337
|
if (didRetry) return; // Retry was initiated, don't proceed to compaction
|
|
8224
8338
|
}
|
|
8339
|
+
// Clear the reminder continuation flag after processing
|
|
8340
|
+
if (isReminderContinuationError) {
|
|
8341
|
+
this.#todoReminderContinuationGeneration = undefined;
|
|
8342
|
+
}
|
|
8225
8343
|
if (this.#retryAttempt > 0) {
|
|
8226
8344
|
// A prior retry ended on a non-retryable (terminal) message: emit
|
|
8227
8345
|
// the terminal retry-end and reset so observers clear retry state.
|
|
@@ -8240,7 +8358,7 @@ export class AgentSession {
|
|
|
8240
8358
|
const compactionTask = this.#schedulePostPromptTask(
|
|
8241
8359
|
async () => {
|
|
8242
8360
|
if (this.#isDisposed || this.#sessionAdmissionClosing) return;
|
|
8243
|
-
await this.#checkCompaction(msg, true, undefined, activePromptHandle);
|
|
8361
|
+
await this.#checkCompaction(msg, true, undefined, activePromptHandle, undefined, terminalSdkOwnership);
|
|
8244
8362
|
},
|
|
8245
8363
|
{ resourceRunId: activePromptHandle },
|
|
8246
8364
|
);
|
|
@@ -8466,10 +8584,12 @@ export class AgentSession {
|
|
|
8466
8584
|
/** Internal predecessor terminal event sequestered while waiting behind selection. */
|
|
8467
8585
|
deferredPredecessorAgentEnd?: AgentSessionEvent;
|
|
8468
8586
|
/** Internal causal SDK owner captured when this continuation was scheduled. */
|
|
8469
|
-
|
|
8587
|
+
sdkOwnership?: SdkContinuationOwnership;
|
|
8588
|
+
/** Disable managed fallback retries for this continuation (used for terminal server-initiated turns). */
|
|
8589
|
+
disableManagedFallback?: boolean;
|
|
8470
8590
|
}): Promise<void> {
|
|
8471
8591
|
const continuationAdmission = this.#captureScheduledContinuationAdmission();
|
|
8472
|
-
const
|
|
8592
|
+
const scheduledSdkOwnership = options?.sdkOwnership;
|
|
8473
8593
|
const selectionFenceGeneration =
|
|
8474
8594
|
options?.selectionFenceGeneration ??
|
|
8475
8595
|
this.#selectionFenceGenerationContext.getStore() ??
|
|
@@ -8491,7 +8611,7 @@ export class AgentSession {
|
|
|
8491
8611
|
generation: deferredPromptGeneration,
|
|
8492
8612
|
selectionFenceGeneration,
|
|
8493
8613
|
deferredPredecessorAgentEnd,
|
|
8494
|
-
|
|
8614
|
+
sdkOwnership: scheduledSdkOwnership,
|
|
8495
8615
|
});
|
|
8496
8616
|
} finally {
|
|
8497
8617
|
// The recursive call synchronously re-reserved its settlement
|
|
@@ -8611,14 +8731,21 @@ export class AgentSession {
|
|
|
8611
8731
|
}
|
|
8612
8732
|
const predecessorAgentEnd =
|
|
8613
8733
|
this.#claimDeferredAgentEndForContinuation(predecessorAgentEndHold);
|
|
8734
|
+
const predecessorScope = (
|
|
8735
|
+
predecessorAgentEnd as (AgentSessionEvent & { scope?: AttemptScope }) | undefined
|
|
8736
|
+
)?.scope;
|
|
8737
|
+
const predecessorSdkOwnership = this.#captureSdkContinuationOwnership(predecessorScope);
|
|
8614
8738
|
let predecessorAccepted = false;
|
|
8615
8739
|
const releasePredecessor = () => {
|
|
8616
8740
|
if (predecessorAccepted) return;
|
|
8617
8741
|
predecessorAccepted = true;
|
|
8618
|
-
|
|
8742
|
+
if (startsQueuedSuccessor)
|
|
8743
|
+
this.#restoreDeferredAgentEndAfterContinuationFailure(predecessorAgentEnd);
|
|
8744
|
+
else this.#releaseDeferredAgentEndLease(predecessorAgentEnd);
|
|
8619
8745
|
};
|
|
8620
8746
|
const hasQueuedMessages = this.agent.hasQueuedMessages();
|
|
8621
8747
|
const startsQueuedSuccessor =
|
|
8748
|
+
options?.maintenanceContinuation !== true &&
|
|
8622
8749
|
hasQueuedMessages &&
|
|
8623
8750
|
(options?.continueQueuedOnly === true ||
|
|
8624
8751
|
this.agent.state.messages.at(-1)?.role === "assistant");
|
|
@@ -8627,7 +8754,7 @@ export class AgentSession {
|
|
|
8627
8754
|
: this.agent.continue.bind(this.agent);
|
|
8628
8755
|
try {
|
|
8629
8756
|
await continueQueued({
|
|
8630
|
-
...this.#managedFallbackPromptOptions(),
|
|
8757
|
+
...(options?.disableManagedFallback ? { fallbackManaged: false } : this.#managedFallbackPromptOptions()),
|
|
8631
8758
|
maintenanceContinuation: options?.maintenanceContinuation,
|
|
8632
8759
|
// Reset only after continue() has claimed the queued turn. Skipped or stale
|
|
8633
8760
|
// continuations retain predecessor accounting, and resetAttemptBudget keeps
|
|
@@ -8637,13 +8764,21 @@ export class AgentSession {
|
|
|
8637
8764
|
// agent_start (review P1); their queued messages are in-run
|
|
8638
8765
|
// consumptions, not own-run promotions.
|
|
8639
8766
|
const startsOwn = options?.maintenanceContinuation !== true;
|
|
8640
|
-
const
|
|
8641
|
-
|
|
8642
|
-
|
|
8767
|
+
const inheritedSdkOwnership =
|
|
8768
|
+
options?.continueQueuedOnly || startsQueuedSuccessor
|
|
8769
|
+
? undefined
|
|
8770
|
+
: (scheduledSdkOwnership ?? predecessorSdkOwnership);
|
|
8771
|
+
const inheritedPredecessorScope =
|
|
8772
|
+
options?.continueQueuedOnly || startsQueuedSuccessor
|
|
8773
|
+
? undefined
|
|
8774
|
+
: (inheritedSdkOwnership?.scope ?? predecessorScope);
|
|
8643
8775
|
const consumedSdkRunTokens = acceptance.consumedQueuedMessages
|
|
8644
8776
|
.map(message => this.#sdkRunTokensByQueuedMessage.get(message))
|
|
8645
8777
|
.filter((token): token is string => token !== undefined);
|
|
8646
|
-
const sdkRunToken = consumedSdkRunTokens[0]
|
|
8778
|
+
const sdkRunToken = inheritedSdkOwnership?.token ?? consumedSdkRunTokens[0];
|
|
8779
|
+
const sdkRunTokens = inheritedSdkOwnership
|
|
8780
|
+
? [...new Set([...inheritedSdkOwnership.cohort, ...consumedSdkRunTokens])]
|
|
8781
|
+
: consumedSdkRunTokens;
|
|
8647
8782
|
this.#fireQueuedPromotionHooks(acceptance.consumedQueuedMessages, {
|
|
8648
8783
|
startsOwnRun: startsOwn,
|
|
8649
8784
|
});
|
|
@@ -8651,7 +8786,8 @@ export class AgentSession {
|
|
|
8651
8786
|
this.#acceptSdkAttemptRun(
|
|
8652
8787
|
handle,
|
|
8653
8788
|
sdkRunToken,
|
|
8654
|
-
|
|
8789
|
+
sdkRunTokens.length > 0 ? sdkRunTokens : undefined,
|
|
8790
|
+
inheritedPredecessorScope,
|
|
8655
8791
|
);
|
|
8656
8792
|
options?.onRunAccepted?.(handle);
|
|
8657
8793
|
// Keep the queued token available through the acceptance callback;
|
|
@@ -8778,7 +8914,11 @@ export class AgentSession {
|
|
|
8778
8914
|
return compactionSettings.autoContinue === false ? "auto_continue_disabled_non_resumable_tail" : undefined;
|
|
8779
8915
|
}
|
|
8780
8916
|
|
|
8781
|
-
async #scheduleOverflowRetryContinuation(
|
|
8917
|
+
async #scheduleOverflowRetryContinuation(
|
|
8918
|
+
generation: number,
|
|
8919
|
+
resourceRunId?: string,
|
|
8920
|
+
sdkOwnership?: SdkContinuationOwnership,
|
|
8921
|
+
): Promise<boolean> {
|
|
8782
8922
|
this.#stripOverflowFailedTurnForRetry();
|
|
8783
8923
|
const snapshot = await this.#compactionStateSnapshot();
|
|
8784
8924
|
if (
|
|
@@ -8795,6 +8935,7 @@ export class AgentSession {
|
|
|
8795
8935
|
generation,
|
|
8796
8936
|
suppressPredecessorAgentEnd: true,
|
|
8797
8937
|
resourceRunId,
|
|
8938
|
+
sdkOwnership,
|
|
8798
8939
|
onSkip: reason => this.#logCompactionContinuationSkipped("overflow_retry", reason),
|
|
8799
8940
|
onError: error => this.#logCompactionContinuationError("overflow_retry", error),
|
|
8800
8941
|
});
|
|
@@ -8803,7 +8944,7 @@ export class AgentSession {
|
|
|
8803
8944
|
|
|
8804
8945
|
const compactionSettings = this.settings.getGroup("compaction");
|
|
8805
8946
|
if (compactionSettings.autoContinue !== false) {
|
|
8806
|
-
this.#scheduleAutoContinuePrompt(generation, false, resourceRunId);
|
|
8947
|
+
this.#scheduleAutoContinuePrompt(generation, false, resourceRunId, undefined, undefined, sdkOwnership);
|
|
8807
8948
|
return true;
|
|
8808
8949
|
}
|
|
8809
8950
|
|
|
@@ -8817,7 +8958,7 @@ export class AgentSession {
|
|
|
8817
8958
|
resourceRunId?: string,
|
|
8818
8959
|
deferredSelectionFenceGeneration?: number,
|
|
8819
8960
|
deferredPredecessorAgentEnd?: AgentSessionEvent,
|
|
8820
|
-
|
|
8961
|
+
sdkOwnership?: SdkContinuationOwnership,
|
|
8821
8962
|
): void {
|
|
8822
8963
|
if (this.#sessionTransitionKind !== undefined || this.#handoffTransitionActive) {
|
|
8823
8964
|
this.#deferredAutoContinueDuringTransition = () =>
|
|
@@ -8827,14 +8968,16 @@ export class AgentSession {
|
|
|
8827
8968
|
resourceRunId,
|
|
8828
8969
|
deferredSelectionFenceGeneration,
|
|
8829
8970
|
deferredPredecessorAgentEnd,
|
|
8830
|
-
|
|
8971
|
+
sdkOwnership,
|
|
8831
8972
|
);
|
|
8832
8973
|
return;
|
|
8833
8974
|
}
|
|
8834
8975
|
const scheduledGeneration = generation;
|
|
8835
|
-
const
|
|
8836
|
-
|
|
8837
|
-
|
|
8976
|
+
const scheduledSdkOwnership =
|
|
8977
|
+
sdkOwnership ??
|
|
8978
|
+
this.#captureSdkContinuationOwnership(
|
|
8979
|
+
(deferredPredecessorAgentEnd as (AgentSessionEvent & { scope?: AttemptScope }) | undefined)?.scope,
|
|
8980
|
+
);
|
|
8838
8981
|
const continuationAuthorized = async (
|
|
8839
8982
|
signal: AbortSignal,
|
|
8840
8983
|
hasPendingNextTurnMessages = false,
|
|
@@ -8891,7 +9034,7 @@ export class AgentSession {
|
|
|
8891
9034
|
resourceRunId,
|
|
8892
9035
|
selectionFenceGeneration,
|
|
8893
9036
|
predecessorAgentEnd,
|
|
8894
|
-
|
|
9037
|
+
scheduledSdkOwnership,
|
|
8895
9038
|
);
|
|
8896
9039
|
} finally {
|
|
8897
9040
|
this.#endSelectionFenceDeferralTracking(selectionFenceGeneration);
|
|
@@ -8939,7 +9082,9 @@ export class AgentSession {
|
|
|
8939
9082
|
promptText,
|
|
8940
9083
|
{
|
|
8941
9084
|
skipPostPromptRecoveryWait: true,
|
|
8942
|
-
sdkRunToken:
|
|
9085
|
+
sdkRunToken: scheduledSdkOwnership?.token,
|
|
9086
|
+
sdkRunTokens: scheduledSdkOwnership?.cohort,
|
|
9087
|
+
sdkPredecessorScope: scheduledSdkOwnership?.scope,
|
|
8943
9088
|
skipCompactionCheck: true,
|
|
8944
9089
|
predecessorAgentEndHold,
|
|
8945
9090
|
onFinalPreflight: ({ hasPendingNextTurnMessages }) =>
|
|
@@ -9875,7 +10020,12 @@ export class AgentSession {
|
|
|
9875
10020
|
type: "agent_start",
|
|
9876
10021
|
...(sdkRunToken ? { sdkRunToken } : {}),
|
|
9877
10022
|
...(deliveryScope
|
|
9878
|
-
? {
|
|
10023
|
+
? {
|
|
10024
|
+
sdkRunTokens: this.#sdkRunCohortsByAttemptScope.get(deliveryScope as AttemptScope),
|
|
10025
|
+
lifecycleScope:
|
|
10026
|
+
this.#lifecycleScopesByAttemptScope.get(deliveryScope as AttemptScope) ??
|
|
10027
|
+
(deliveryScope as AttemptScope),
|
|
10028
|
+
}
|
|
9879
10029
|
: {}),
|
|
9880
10030
|
},
|
|
9881
10031
|
undefined,
|
|
@@ -9893,17 +10043,19 @@ export class AgentSession {
|
|
|
9893
10043
|
deliveryScope,
|
|
9894
10044
|
);
|
|
9895
10045
|
} else if (event.type === "agent_end") {
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
);
|
|
10046
|
+
const extensionEvent = {
|
|
10047
|
+
type: "agent_end" as const,
|
|
10048
|
+
messages: event.messages,
|
|
10049
|
+
stopReason: event.stopReason,
|
|
10050
|
+
maintenanceOutcome: event.maintenanceOutcome,
|
|
10051
|
+
...(sdkRunToken ? { sdkRunToken } : {}),
|
|
10052
|
+
};
|
|
10053
|
+
// Keep the Agent-claimed owner OUTSIDE the public extension event and
|
|
10054
|
+
// its replaceable side channel. Only the owning session may attest
|
|
10055
|
+
// this exact projected event to the SDK bus.
|
|
10056
|
+
const terminalOwner = getAgentTerminalOwnerContext(event);
|
|
10057
|
+
if (terminalOwner) this.#terminalOwnerByExtensionEvent.set(extensionEvent, terminalOwner);
|
|
10058
|
+
await this.#extensionRunner.emit(extensionEvent, undefined, deliveryScope);
|
|
9907
10059
|
} else if (event.type === "turn_start") {
|
|
9908
10060
|
const hookEvent: TurnStartEvent = {
|
|
9909
10061
|
type: "turn_start",
|
|
@@ -10110,6 +10262,22 @@ export class AgentSession {
|
|
|
10110
10262
|
this.#abortActiveMidRunBarriers();
|
|
10111
10263
|
this.#compactionQueuedDeliveryArmed = false;
|
|
10112
10264
|
if (this.#unsubscribeAgent) {
|
|
10265
|
+
// This accepted cohort cannot observe its terminal after the bridge is
|
|
10266
|
+
// removed. Reject only that captured owner; queued roots and already
|
|
10267
|
+
// publishing terminals retain their independently owned publication.
|
|
10268
|
+
const ownership = this.#captureSdkContinuationOwnership(this.#activeAttemptScope);
|
|
10269
|
+
if (ownership) {
|
|
10270
|
+
const failure = Object.assign(
|
|
10271
|
+
new Error("Agent event bridge disconnected before SDK terminal publication."),
|
|
10272
|
+
{ code: "cancelled" },
|
|
10273
|
+
);
|
|
10274
|
+
for (const token of ownership.cohort) {
|
|
10275
|
+
const publication = this.#sdkTerminalPublications.get(token);
|
|
10276
|
+
if (!publication || this.#publishingSdkTerminals.has(publication)) continue;
|
|
10277
|
+
publication.reject(failure);
|
|
10278
|
+
this.#sdkTerminalPublications.delete(token);
|
|
10279
|
+
}
|
|
10280
|
+
}
|
|
10113
10281
|
this.#unsubscribeAgent();
|
|
10114
10282
|
this.#unsubscribeAgent = undefined;
|
|
10115
10283
|
}
|
|
@@ -10267,6 +10435,11 @@ export class AgentSession {
|
|
|
10267
10435
|
// settle every accepted SDK handle now so consumed submissions cannot wait
|
|
10268
10436
|
// forever for an agent_end that teardown deliberately suppresses.
|
|
10269
10437
|
this.#terminalizeQueuedSdkWorkForSessionTransition(this.#queuedMessagesForSessionTransition());
|
|
10438
|
+
const publicationFailure = Object.assign(new Error("Session disposed before SDK terminal publication."), {
|
|
10439
|
+
code: "cancelled",
|
|
10440
|
+
});
|
|
10441
|
+
for (const publication of this.#sdkTerminalPublications.values()) publication.reject(publicationFailure);
|
|
10442
|
+
this.#sdkTerminalPublications.clear();
|
|
10270
10443
|
// Invalidate every coordinator event admitted before disposal. Handlers may
|
|
10271
10444
|
// still unwind, but their captured generation can no longer enqueue a write.
|
|
10272
10445
|
this.#coordinatorPersistGeneration += 1;
|
|
@@ -10636,6 +10809,11 @@ export class AgentSession {
|
|
|
10636
10809
|
* at `timeoutMs` so a wedged subprocess can't stall process exit.
|
|
10637
10810
|
*/
|
|
10638
10811
|
async disposeChildSubprocesses(timeoutMs = SIGNAL_TEARDOWN_TIMEOUT_MS): Promise<void> {
|
|
10812
|
+
this.#evalExecutionDisposing = true;
|
|
10813
|
+
this.abortEval();
|
|
10814
|
+
const evalExecutionsSettled = this.#waitForEvalExecutionsToSettle(timeoutMs).then(settled => {
|
|
10815
|
+
if (!settled) logger.warn("signal teardown: active eval executions remain unsettled");
|
|
10816
|
+
});
|
|
10639
10817
|
const sessionId = this.sessionManager.getSessionId();
|
|
10640
10818
|
const kernelOwnerId = this.#evalKernelOwnerId;
|
|
10641
10819
|
this.#unregisterResourceGc?.();
|
|
@@ -10645,6 +10823,7 @@ export class AgentSession {
|
|
|
10645
10823
|
this.#unregisterDelegationHintSettings?.();
|
|
10646
10824
|
this.#unregisterDelegationHintSettings = undefined;
|
|
10647
10825
|
const work = Promise.allSettled([
|
|
10826
|
+
evalExecutionsSettled,
|
|
10648
10827
|
// kill:true so a forced exit also reaps spawned-app Chrome we own (headless
|
|
10649
10828
|
// always closes; connected/attached browsers only disconnect — never killed).
|
|
10650
10829
|
releaseTabsForOwner(sessionId, { kill: true }).catch((error: unknown) =>
|
|
@@ -10673,7 +10852,8 @@ export class AgentSession {
|
|
|
10673
10852
|
logger.warn("signal teardown: tool session transition cleanups failed", { error }),
|
|
10674
10853
|
),
|
|
10675
10854
|
]);
|
|
10676
|
-
await Promise.race([work, Bun.sleep(timeoutMs)]);
|
|
10855
|
+
const completed = await Promise.race([work.then(() => true), Bun.sleep(timeoutMs).then(() => false)]);
|
|
10856
|
+
if (!completed) logger.warn("signal teardown: cleanup exceeded its bounded caller deadline");
|
|
10677
10857
|
}
|
|
10678
10858
|
|
|
10679
10859
|
#rebindProviderSessionState(providerSessionState: Map<string, ProviderSessionState>): void {
|
|
@@ -12322,7 +12502,9 @@ export class AgentSession {
|
|
|
12322
12502
|
*/
|
|
12323
12503
|
get messages(): AgentMessage[] {
|
|
12324
12504
|
const messages = this.agent.state.messages;
|
|
12325
|
-
return messages.some(
|
|
12505
|
+
return messages.some(
|
|
12506
|
+
message => message.role === "custom" && this.#isEphemeralCustomMessageType(message.customType),
|
|
12507
|
+
)
|
|
12326
12508
|
? this.#withoutEphemeralCustomMessages(messages)
|
|
12327
12509
|
: messages;
|
|
12328
12510
|
}
|
|
@@ -13463,6 +13645,36 @@ export class AgentSession {
|
|
|
13463
13645
|
}
|
|
13464
13646
|
}
|
|
13465
13647
|
|
|
13648
|
+
/**
|
|
13649
|
+
* The loaded skill a prompt's text dispatches to, or undefined when `prompt`
|
|
13650
|
+
* would submit it as ordinary text (unknown or disabled `/skill:` names,
|
|
13651
|
+
* chains, or attached images). Single source for dispatch and for callers
|
|
13652
|
+
* that must mirror it, such as startup title seeding.
|
|
13653
|
+
*/
|
|
13654
|
+
resolvePromptSkillInvocation(text: string, images?: readonly unknown[]): ParsedSkillInvocation | undefined {
|
|
13655
|
+
if (images?.length || !text.startsWith("/") || !isNamespacedSkillSlashCommandName(text.slice(1))) return;
|
|
13656
|
+
const skillCommands = new Map(this.skills.map(skill => [getSkillSlashCommandName(skill), skill]));
|
|
13657
|
+
const invocations = parseSkillInvocations(text, skillCommands);
|
|
13658
|
+
return invocations.length === 1 ? invocations[0] : undefined;
|
|
13659
|
+
}
|
|
13660
|
+
|
|
13661
|
+
/**
|
|
13662
|
+
* Whether `prompt` intercepts this slash text as an extension or custom/MCP
|
|
13663
|
+
* command. Used to keep command arguments away from the title model. Mirrors the
|
|
13664
|
+
* command lookup in `#tryExecuteExtensionCommand` / `#tryExecuteCustomCommand`
|
|
13665
|
+
* without executing anything.
|
|
13666
|
+
*/
|
|
13667
|
+
isLocallyHandledSlashCommand(text: string): boolean {
|
|
13668
|
+
if (!text.startsWith("/")) return false;
|
|
13669
|
+
const spaceIndex = text.indexOf(" ");
|
|
13670
|
+
const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
|
|
13671
|
+
return (
|
|
13672
|
+
this.#extensionRunner?.getCommand(commandName) !== undefined ||
|
|
13673
|
+
this.#customCommands.some(c => c.command.name === commandName) ||
|
|
13674
|
+
this.#mcpPromptCommands.some(c => c.command.name === commandName)
|
|
13675
|
+
);
|
|
13676
|
+
}
|
|
13677
|
+
|
|
13466
13678
|
async #promptInternal(
|
|
13467
13679
|
text: string,
|
|
13468
13680
|
options: PromptOptions | undefined,
|
|
@@ -13484,38 +13696,29 @@ export class AgentSession {
|
|
|
13484
13696
|
if (owner && !owner.released) throw this.#sessionAdmissionBusyError();
|
|
13485
13697
|
const expandPromptTemplates = options?.expandPromptTemplates ?? true;
|
|
13486
13698
|
|
|
13487
|
-
if (
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
? { onPreflightAcceptCommit: options.onPreflightAcceptCommit }
|
|
13511
|
-
: {}),
|
|
13512
|
-
...(options?.preflightSignal ? { preflightSignal: options.preflightSignal } : {}),
|
|
13513
|
-
...(options?.sdkRunCapability ? { sdkRunCapability: options.sdkRunCapability } : {}),
|
|
13514
|
-
}
|
|
13515
|
-
: undefined,
|
|
13516
|
-
);
|
|
13517
|
-
return;
|
|
13518
|
-
}
|
|
13699
|
+
if (expandPromptTemplates) {
|
|
13700
|
+
const invocation = this.resolvePromptSkillInvocation(text, options?.images);
|
|
13701
|
+
if (invocation) {
|
|
13702
|
+
await this.invokeSkill(
|
|
13703
|
+
invocation.skill.name,
|
|
13704
|
+
invocation.args,
|
|
13705
|
+
options?.onPreflightAccepted ||
|
|
13706
|
+
options?.onPreflightAcceptCommit ||
|
|
13707
|
+
options?.preflightSignal ||
|
|
13708
|
+
internalOptions?.sdkRunToken
|
|
13709
|
+
? {
|
|
13710
|
+
...(options?.onPreflightAccepted
|
|
13711
|
+
? { onPreflightAccepted: options.onPreflightAccepted }
|
|
13712
|
+
: {}),
|
|
13713
|
+
...(options?.onPreflightAcceptCommit
|
|
13714
|
+
? { onPreflightAcceptCommit: options.onPreflightAcceptCommit }
|
|
13715
|
+
: {}),
|
|
13716
|
+
...(options?.preflightSignal ? { preflightSignal: options.preflightSignal } : {}),
|
|
13717
|
+
...(options?.sdkRunCapability ? { sdkRunCapability: options.sdkRunCapability } : {}),
|
|
13718
|
+
}
|
|
13719
|
+
: undefined,
|
|
13720
|
+
);
|
|
13721
|
+
return;
|
|
13519
13722
|
}
|
|
13520
13723
|
}
|
|
13521
13724
|
|
|
@@ -13932,6 +14135,8 @@ export class AgentSession {
|
|
|
13932
14135
|
| "preflightSignal"
|
|
13933
14136
|
> & {
|
|
13934
14137
|
sdkRunToken?: string;
|
|
14138
|
+
sdkRunTokens?: string[];
|
|
14139
|
+
sdkPredecessorScope?: AttemptScope;
|
|
13935
14140
|
prependMessages?: AgentMessage[];
|
|
13936
14141
|
skipPostPromptRecoveryWait?: boolean;
|
|
13937
14142
|
predecessorAgentEndHold?: symbol;
|
|
@@ -14002,6 +14207,7 @@ export class AgentSession {
|
|
|
14002
14207
|
let skipPostPromptRecoveryWait =
|
|
14003
14208
|
options?.skipPostPromptRecoveryWait === true || options?.sdkRunToken !== undefined;
|
|
14004
14209
|
let promptAttemptScope: AttemptScope | undefined;
|
|
14210
|
+
let promptSdkPublication: Promise<void> | undefined;
|
|
14005
14211
|
let hindsightRecall: string | undefined;
|
|
14006
14212
|
try {
|
|
14007
14213
|
this.#throwIfPromptPreflightCancelled(generation, preflightSignal);
|
|
@@ -14302,10 +14508,26 @@ export class AgentSession {
|
|
|
14302
14508
|
...(options?.sdkRunToken ? { sdkRunToken: options.sdkRunToken } : {}),
|
|
14303
14509
|
onRunAccepted: (handle: AttemptRunHandle) => {
|
|
14304
14510
|
promptAttemptScope = handle?.scope;
|
|
14305
|
-
|
|
14511
|
+
// A synthetic recovery prompt can make Agent retire the old managed
|
|
14512
|
+
// run at method entry. Suppress only that captured predecessor once
|
|
14513
|
+
// the replacement accepts; pre-acceptance failures still publish it.
|
|
14514
|
+
if (handle && options?.sdkPredecessorScope) {
|
|
14515
|
+
const predecessor = this.#claimDeferredAgentEndForContinuation(
|
|
14516
|
+
this.#reserveDeferredAgentEndForContinuation(options.sdkPredecessorScope),
|
|
14517
|
+
);
|
|
14518
|
+
this.#releaseDeferredAgentEndLease(predecessor);
|
|
14519
|
+
}
|
|
14520
|
+
if (handle)
|
|
14521
|
+
this.#acceptSdkAttemptRun(
|
|
14522
|
+
handle,
|
|
14523
|
+
options?.sdkRunToken,
|
|
14524
|
+
options?.sdkRunTokens,
|
|
14525
|
+
options?.sdkPredecessorScope,
|
|
14526
|
+
);
|
|
14306
14527
|
else this.#acceptRunHandle(handle);
|
|
14307
14528
|
if (handle && options?.sdkRunToken) {
|
|
14308
14529
|
this.#activeSdkRunToken = options.sdkRunToken;
|
|
14530
|
+
promptSdkPublication = this.#sdkTerminalPublications.get(options.sdkRunToken)?.promise;
|
|
14309
14531
|
}
|
|
14310
14532
|
options?.onRunAccepted?.(handle);
|
|
14311
14533
|
options?.admissionLease?.release();
|
|
@@ -14388,7 +14610,11 @@ export class AgentSession {
|
|
|
14388
14610
|
this.#releaseIrcRosterClaim(rosterClaim.token, rosterClaim.epoch);
|
|
14389
14611
|
}
|
|
14390
14612
|
this.#releaseDeferredAgentEndContinuation(predecessorAgentEndHold);
|
|
14391
|
-
await this.#settleEndedInFlight(
|
|
14613
|
+
await this.#settleEndedInFlight(
|
|
14614
|
+
inFlightPrompt,
|
|
14615
|
+
skipPostPromptRecoveryWait ? "publication" : "full",
|
|
14616
|
+
promptSdkPublication,
|
|
14617
|
+
);
|
|
14392
14618
|
}
|
|
14393
14619
|
}
|
|
14394
14620
|
|
|
@@ -14676,10 +14902,7 @@ export class AgentSession {
|
|
|
14676
14902
|
// prompt still in preflight, aborting) has no run to steer. Ordinary steers
|
|
14677
14903
|
// become a sequential follow-up owned by the next turn; SDK turn-bound
|
|
14678
14904
|
// steers fail closed rather than being delivered to a successor run.
|
|
14679
|
-
if (
|
|
14680
|
-
options?.expectedSdkRunToken !== undefined &&
|
|
14681
|
-
this.#activeSdkRunToken !== options.expectedSdkRunToken
|
|
14682
|
-
)
|
|
14905
|
+
if (options?.expectedSdkRunToken !== undefined && this.#activeSdkRunToken !== options.expectedSdkRunToken)
|
|
14683
14906
|
throw Object.assign(new Error("The expected SDK run is not active."), { code: "turn_not_active" });
|
|
14684
14907
|
const admission = this.agent.steer(message, options?.forceOneAtATime ? { forceOneAtATime: true } : undefined);
|
|
14685
14908
|
if (!admission.admitted) {
|
|
@@ -14736,8 +14959,8 @@ export class AgentSession {
|
|
|
14736
14959
|
/**
|
|
14737
14960
|
* One-shot preflight-abort binding: an invocation cancelled after its queue
|
|
14738
14961
|
* admission must cancel the submission it admitted, so an aborted dispatch
|
|
14739
|
-
* can never execute later.
|
|
14740
|
-
*
|
|
14962
|
+
* can never execute later. Explicit and implicitly diverted queue admissions
|
|
14963
|
+
* share this helper so their cancellation semantics cannot diverge
|
|
14741
14964
|
* (exact-head review P1).
|
|
14742
14965
|
*/
|
|
14743
14966
|
#bindPreflightAbortCancellation(
|
|
@@ -15418,6 +15641,7 @@ export class AgentSession {
|
|
|
15418
15641
|
forceOneAtATime: sequential !== undefined,
|
|
15419
15642
|
createDisplayEntry: false,
|
|
15420
15643
|
trackExternalFollowUp: false,
|
|
15644
|
+
sdkRunToken: this.#activeSdkRunToken,
|
|
15421
15645
|
});
|
|
15422
15646
|
if (this.#abortUnwind && !sequential) this.#abortUnwindSteerFallbacks.push(appMessage);
|
|
15423
15647
|
// The chip now describes follow-up work: keep its mode and identity
|
|
@@ -15448,6 +15672,7 @@ export class AgentSession {
|
|
|
15448
15672
|
forceOneAtATime: options?.followUpQueuePolicy === "sequential",
|
|
15449
15673
|
createDisplayEntry: false,
|
|
15450
15674
|
trackExternalFollowUp: false,
|
|
15675
|
+
sdkRunToken: this.#activeSdkRunToken,
|
|
15451
15676
|
});
|
|
15452
15677
|
this.#bindCustomDisplayEntry(appMessage, "followUp");
|
|
15453
15678
|
// The session can report streaming while no agent loop owns the queue
|
|
@@ -15869,12 +16094,13 @@ export class AgentSession {
|
|
|
15869
16094
|
if (this.#isLiveTurnBusy() && !waitedForAbortUnwind) {
|
|
15870
16095
|
if (options?.onPreflightAcceptCommit) await options.onPreflightAcceptCommit();
|
|
15871
16096
|
assertPreflightStillOpen();
|
|
15872
|
-
await this.#queueSteer(text, images, {
|
|
16097
|
+
const queuedSteer = await this.#queueSteer(text, images, {
|
|
15873
16098
|
claimsGenuineUserIntent: true,
|
|
15874
|
-
onPromoted:
|
|
16099
|
+
onPromoted: onQueuedPromoted,
|
|
15875
16100
|
external: true,
|
|
15876
16101
|
sdkRunToken: internalOptions?.sdkRunToken,
|
|
15877
16102
|
});
|
|
16103
|
+
this.#bindPreflightAbortCancellation(options?.preflightSignal, queuedSteer);
|
|
15878
16104
|
// Dispatch-race disposition (#4668 review P1): the SDK snapshot-decided
|
|
15879
16105
|
// this submission starts its own turn (idle at dispatch), but the
|
|
15880
16106
|
// session began streaming before sendUserMessage ran, so the message
|
|
@@ -15884,8 +16110,15 @@ export class AgentSession {
|
|
|
15884
16110
|
// would terminalize the accepted request as an own-run completion
|
|
15885
16111
|
// before it is consumed. Report the internal in-run disposition so the
|
|
15886
16112
|
// runtime attaches the correlation to the in-flight run instead.
|
|
15887
|
-
|
|
15888
|
-
|
|
16113
|
+
try {
|
|
16114
|
+
assertPreflightStillOpen();
|
|
16115
|
+
options?.onDispatchDisposition?.({ startsOwnRun: false });
|
|
16116
|
+
options?.onPreflightAccepted?.();
|
|
16117
|
+
assertPreflightStillOpen();
|
|
16118
|
+
} catch (error) {
|
|
16119
|
+
queuedSteer.cancel();
|
|
16120
|
+
throw error;
|
|
16121
|
+
}
|
|
15889
16122
|
return;
|
|
15890
16123
|
}
|
|
15891
16124
|
|
|
@@ -16816,6 +17049,12 @@ export class AgentSession {
|
|
|
16816
17049
|
if (!lineageIdHash) return undefined;
|
|
16817
17050
|
return this.#promptGeneration;
|
|
16818
17051
|
}
|
|
17052
|
+
getTerminalRunOwnerForEvent(event: object): AgentTerminalOwnerContext | undefined {
|
|
17053
|
+
return this.#terminalOwnerByExtensionEvent.get(event);
|
|
17054
|
+
}
|
|
17055
|
+
getRunOwnerDomain(handle: string): RunCancellationDomain | undefined {
|
|
17056
|
+
return this.agent.resourceLedger.lookupDomain(handle);
|
|
17057
|
+
}
|
|
16819
17058
|
/**
|
|
16820
17059
|
* Logical endpoint used to key owned-registration lineage bindings.
|
|
16821
17060
|
* Subagents inherit the parent's AsyncJobManager, whose completion callback
|
|
@@ -17974,8 +18213,12 @@ export class AgentSession {
|
|
|
17974
18213
|
}
|
|
17975
18214
|
|
|
17976
18215
|
options?.onMutationStarted?.();
|
|
17977
|
-
|
|
18216
|
+
const cause = options?.cause ?? "user-selection";
|
|
18217
|
+
if (cause === "user-selection") this.markUserModelSelection();
|
|
18218
|
+
this.#setModelAuthoritatively(model, cause);
|
|
18219
|
+
if (cause === "user-selection") this.#unavailableModelProfile = undefined;
|
|
17978
18220
|
this.#seedSessionCanonicalVariant(model);
|
|
18221
|
+
if (cause === "user-selection") this.#recordUserCanonicalVariantSelection();
|
|
17979
18222
|
this.sessionManager.appendModelChange(`${model.provider}/${model.id}`, role);
|
|
17980
18223
|
this.settings.setModelRole(
|
|
17981
18224
|
role,
|
|
@@ -17983,7 +18226,7 @@ export class AgentSession {
|
|
|
17983
18226
|
);
|
|
17984
18227
|
// Only an explicit user selection starts a new fallback epoch. Internal
|
|
17985
18228
|
// fallback switches must preserve the exhausted-model set while advancing.
|
|
17986
|
-
if (role === "default" &&
|
|
18229
|
+
if (role === "default" && cause === "user-selection") {
|
|
17987
18230
|
this.#fallbackTransitionGeneration++;
|
|
17988
18231
|
this.#defaultFallbackController = undefined;
|
|
17989
18232
|
this.#defaultFallbackExhaustedLastTurn = false;
|
|
@@ -18020,12 +18263,41 @@ export class AgentSession {
|
|
|
18020
18263
|
|
|
18021
18264
|
setActiveModelProfile(name: string | undefined): void {
|
|
18022
18265
|
this.#activeModelProfile = name;
|
|
18266
|
+
if (name !== undefined) {
|
|
18267
|
+
this.#unavailableModelProfile = undefined;
|
|
18268
|
+
}
|
|
18023
18269
|
}
|
|
18024
18270
|
|
|
18025
18271
|
getActiveModelProfile(): string | undefined {
|
|
18026
18272
|
return this.#activeModelProfile;
|
|
18027
18273
|
}
|
|
18028
18274
|
|
|
18275
|
+
setUnavailableModelProfile(name: string | undefined): void {
|
|
18276
|
+
this.#unavailableModelProfile = name;
|
|
18277
|
+
}
|
|
18278
|
+
|
|
18279
|
+
getUnavailableModelProfile(): string | undefined {
|
|
18280
|
+
return this.#unavailableModelProfile;
|
|
18281
|
+
}
|
|
18282
|
+
|
|
18283
|
+
/** Revision fence for deferred activation after a user model selection. */
|
|
18284
|
+
getUserModelSelectionRevision(): number {
|
|
18285
|
+
return this.#userModelSelectionRevision;
|
|
18286
|
+
}
|
|
18287
|
+
|
|
18288
|
+
/** Latest concrete user choice that seeded or cleared the session's sticky canonical variant. */
|
|
18289
|
+
getUserCanonicalVariantSelection(): { revision: number; canonicalVariant: string | undefined } {
|
|
18290
|
+
return {
|
|
18291
|
+
revision: this.#userCanonicalVariantSelectionRevision,
|
|
18292
|
+
canonicalVariant: this.#userCanonicalVariantSelection,
|
|
18293
|
+
};
|
|
18294
|
+
}
|
|
18295
|
+
|
|
18296
|
+
/** Fence deferred startup profile recovery before an explicit control-surface selection. */
|
|
18297
|
+
markUserModelSelection(): void {
|
|
18298
|
+
this.#userModelSelectionRevision++;
|
|
18299
|
+
}
|
|
18300
|
+
|
|
18029
18301
|
/**
|
|
18030
18302
|
* Re-apply vendor-separated delegation after a profile activation changed the
|
|
18031
18303
|
* role layer. `eagerTasks` is resolved at prompt build time, but under
|
|
@@ -18187,12 +18459,15 @@ export class AgentSession {
|
|
|
18187
18459
|
* Session-scoped only: does not persist `modelProfile.default`.
|
|
18188
18460
|
*/
|
|
18189
18461
|
async activateModelProfileForControl(profileName: string): Promise<boolean> {
|
|
18190
|
-
|
|
18191
|
-
|
|
18192
|
-
|
|
18193
|
-
|
|
18194
|
-
|
|
18195
|
-
|
|
18462
|
+
this.markUserModelSelection();
|
|
18463
|
+
await this.withSdkControlMutation(() =>
|
|
18464
|
+
activateModelProfile({
|
|
18465
|
+
session: this,
|
|
18466
|
+
modelRegistry: this.#modelRegistry,
|
|
18467
|
+
settings: this.settings,
|
|
18468
|
+
profileName,
|
|
18469
|
+
}),
|
|
18470
|
+
);
|
|
18196
18471
|
return this.getActiveModelProfile() === profileName;
|
|
18197
18472
|
}
|
|
18198
18473
|
|
|
@@ -18227,6 +18502,7 @@ export class AgentSession {
|
|
|
18227
18502
|
onAfterActivation?: () => void;
|
|
18228
18503
|
},
|
|
18229
18504
|
): Promise<{ changed: boolean; id: string }> {
|
|
18505
|
+
this.markUserModelSelection();
|
|
18230
18506
|
// Do not hold selection admission while waiting for a scheduled continuation:
|
|
18231
18507
|
// the continuation may need prompt admission to settle the current turn.
|
|
18232
18508
|
await this.waitForIdle();
|
|
@@ -18505,6 +18781,7 @@ export class AgentSession {
|
|
|
18505
18781
|
reason?: TemporaryModelReason;
|
|
18506
18782
|
providerSessionScope?: TemporaryProviderSessionScope;
|
|
18507
18783
|
signal?: AbortSignal;
|
|
18784
|
+
shouldMutate?: () => boolean;
|
|
18508
18785
|
onMutationStarted?: () => void;
|
|
18509
18786
|
},
|
|
18510
18787
|
// biome-ignore lint/suspicious/noConfusingVoidType: Existing session adapters return Promise<void>; a scope is optional.
|
|
@@ -18523,6 +18800,8 @@ export class AgentSession {
|
|
|
18523
18800
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
18524
18801
|
}
|
|
18525
18802
|
if (suppliedScope && this.#temporaryProviderSessionScopes.at(-1)?.token !== suppliedScope) return;
|
|
18803
|
+
if (options?.shouldMutate && !options.shouldMutate()) return;
|
|
18804
|
+
if (options?.cause === "user-selection") this.markUserModelSelection();
|
|
18526
18805
|
options?.onMutationStarted?.();
|
|
18527
18806
|
|
|
18528
18807
|
const isTemporaryOperation = options?.cause === undefined || options.cause === "temporary-operation";
|
|
@@ -18549,6 +18828,9 @@ export class AgentSession {
|
|
|
18549
18828
|
} else {
|
|
18550
18829
|
this.#setModelAuthoritatively(model, options?.cause ?? "temporary-operation");
|
|
18551
18830
|
}
|
|
18831
|
+
if (options?.cause === "user-selection") {
|
|
18832
|
+
this.#unavailableModelProfile = undefined;
|
|
18833
|
+
}
|
|
18552
18834
|
this.sessionManager.appendModelChange(
|
|
18553
18835
|
`${model.provider}/${model.id}`,
|
|
18554
18836
|
options?.persistAsSessionDefault ? "default" : "temporary",
|
|
@@ -18556,12 +18838,36 @@ export class AgentSession {
|
|
|
18556
18838
|
this.settings.getStorage()?.recordModelUsage(`${model.provider}/${model.id}`);
|
|
18557
18839
|
if (options?.persistAsSessionDefault) {
|
|
18558
18840
|
this.#seedSessionCanonicalVariant(model);
|
|
18841
|
+
if (options.cause === "user-selection") this.#recordUserCanonicalVariantSelection();
|
|
18559
18842
|
}
|
|
18560
18843
|
|
|
18561
18844
|
// Apply explicit thinking level if given; otherwise prefer the model's
|
|
18562
18845
|
// configured defaultLevel; otherwise re-clamp the current level.
|
|
18563
18846
|
this.setThinkingLevel(thinkingLevel ?? model.thinking?.defaultLevel ?? this.thinkingLevel);
|
|
18564
|
-
if (options?.persistAsSessionDefault === true
|
|
18847
|
+
if (options?.persistAsSessionDefault === true && options.cause !== "profile-activation") {
|
|
18848
|
+
// Concrete model selection clears session-scoped profile state (#5919).
|
|
18849
|
+
// Materialize durable profiles first (if persisted and active), then reset
|
|
18850
|
+
// without force to preserve durable semantics.
|
|
18851
|
+
if (this.model && this.settings.get("modelProfile.default") !== undefined) {
|
|
18852
|
+
this.materializeActiveDefaultModelProfileAssignment(this.model);
|
|
18853
|
+
}
|
|
18854
|
+
this.#resetSessionScopedModelProfileState({ preserveDefaultConfiguredChain: true });
|
|
18855
|
+
// For user-selection and startup-override causes, also clear stale persisted
|
|
18856
|
+
// defaults via the legacy path when there is no ownership record.
|
|
18857
|
+
if (options.cause === "user-selection" || options.cause === "startup-override") {
|
|
18858
|
+
const ownership = readDurableModelProfileOwnership(this.settings);
|
|
18859
|
+
if (ownership.version === 0) {
|
|
18860
|
+
this.#clearActiveModelProfileForConcreteDefault(options.cause);
|
|
18861
|
+
}
|
|
18862
|
+
}
|
|
18863
|
+
const origin = options.cause === "startup-override" ? "startup-override" : "model_selection";
|
|
18864
|
+
const effectiveLevel = thinkingLevel ?? model.thinking?.defaultLevel ?? this.thinkingLevel;
|
|
18865
|
+
this.setConfiguredModelChain(
|
|
18866
|
+
"default",
|
|
18867
|
+
[formatModelSelectorValue(`${model.provider}/${model.id}`, effectiveLevel)],
|
|
18868
|
+
origin,
|
|
18869
|
+
);
|
|
18870
|
+
}
|
|
18565
18871
|
await this.#syncEditToolModeAfterModelChange(previousEditMode);
|
|
18566
18872
|
} catch (error) {
|
|
18567
18873
|
if (ownsScope) await this.restoreTemporaryProviderSessionScope(scope);
|
|
@@ -18652,8 +18958,15 @@ export class AgentSession {
|
|
|
18652
18958
|
|
|
18653
18959
|
#publishDefaultModelSelection(model: Model, thinkingLevel: ThinkingLevel, systemPrompt: string[] | undefined): void {
|
|
18654
18960
|
this.#clearActiveRetryFallback();
|
|
18961
|
+
// Concrete model selection clears session-scoped profile state (#5919).
|
|
18962
|
+
// IMPORTANT: This is called AFTER durable persistence completes, so the
|
|
18963
|
+
// session-scoped updates occur during the promotion phase after ownership
|
|
18964
|
+
// is committed. Session ownership is captured in the promotion logic above.
|
|
18965
|
+
this.#resetSessionScopedModelProfileState({ preserveDefaultConfiguredChain: true });
|
|
18966
|
+
this.markUserModelSelection();
|
|
18655
18967
|
this.#setModelWithProviderSessionReset(model);
|
|
18656
18968
|
this.#seedSessionCanonicalVariant(model);
|
|
18969
|
+
this.#recordUserCanonicalVariantSelection();
|
|
18657
18970
|
const thinkingLevelChanged = this.#thinkingLevel !== thinkingLevel;
|
|
18658
18971
|
this.#thinkingLevelMutationRevision++;
|
|
18659
18972
|
this.#thinkingLevelLiveMutationRevision++;
|
|
@@ -18663,6 +18976,12 @@ export class AgentSession {
|
|
|
18663
18976
|
this.#pendingThinkingVisibilityControlFailure = undefined;
|
|
18664
18977
|
this.#thinkingLevel = thinkingLevel;
|
|
18665
18978
|
this.agent.setThinkingLevel(toReasoningEffort(thinkingLevel));
|
|
18979
|
+
// Materialize durable profiles after model and thinking level installation
|
|
18980
|
+
// so the persisted default selector matches both the newly installed model
|
|
18981
|
+
// and the selected thinking level.
|
|
18982
|
+
if (this.model && this.settings.get("modelProfile.default") !== undefined) {
|
|
18983
|
+
this.materializeActiveDefaultModelProfileAssignment(this.model);
|
|
18984
|
+
}
|
|
18666
18985
|
if (thinkingLevelChanged) {
|
|
18667
18986
|
const event: AgentSessionEvent = { type: "thinking_level_changed", thinkingLevel };
|
|
18668
18987
|
for (const listener of this.#eventListenerSnapshot) {
|
|
@@ -18848,7 +19167,40 @@ export class AgentSession {
|
|
|
18848
19167
|
});
|
|
18849
19168
|
}
|
|
18850
19169
|
}
|
|
18851
|
-
|
|
19170
|
+
// Concrete model selection clears durable profile ownership (#5919).
|
|
19171
|
+
// If there is an existing ownership record (version > 0), clear it.
|
|
19172
|
+
// If there is no ownership record (version === 0), call the legacy path to
|
|
19173
|
+
// clear stale persisted profiles that no longer match the selection.
|
|
19174
|
+
// The ownership clear is attempted atomically with other model role updates.
|
|
19175
|
+
// If it fails due to concurrent access, we log and continue: the model
|
|
19176
|
+
// selection has been promoted and committed, so the concrete pick is durable.
|
|
19177
|
+
// A stale profile ownership marker will be resolved on the next session startup.
|
|
19178
|
+
const currentOwnership = readDurableModelProfileOwnership(this.settings);
|
|
19179
|
+
if (currentOwnership.version > 0) {
|
|
19180
|
+
try {
|
|
19181
|
+
await commitDurableModelProfileOwnership(this.settings, { kind: "cleared" });
|
|
19182
|
+
} catch (error) {
|
|
19183
|
+
if (error instanceof ModelProfileOwnershipConflictError) {
|
|
19184
|
+
logger.info("Model selection ownership clear deferred due to concurrent access", {
|
|
19185
|
+
code: "default_model_selection_ownership_conflict",
|
|
19186
|
+
disposition: "continue",
|
|
19187
|
+
expectedVersion: error.expectedVersion,
|
|
19188
|
+
actualVersion: error.actualVersion,
|
|
19189
|
+
});
|
|
19190
|
+
} else if (error instanceof InvalidModelProfileOwnershipError) {
|
|
19191
|
+
logger.warn("Invalid model profile ownership marker during selection", {
|
|
19192
|
+
code: "default_model_selection_ownership_invalid",
|
|
19193
|
+
disposition: "continue",
|
|
19194
|
+
});
|
|
19195
|
+
} else {
|
|
19196
|
+
throw error;
|
|
19197
|
+
}
|
|
19198
|
+
}
|
|
19199
|
+
} else {
|
|
19200
|
+
// Legacy path: no ownership record exists. Clear stale persisted defaults
|
|
19201
|
+
// that no longer match the concrete selection.
|
|
19202
|
+
this.#clearActiveModelProfileForConcreteDefault("user-selection");
|
|
19203
|
+
}
|
|
18852
19204
|
options?.onAfterMutation?.();
|
|
18853
19205
|
return { provider: model.provider, modelId: model.id, thinkingLevel: effectiveLevel };
|
|
18854
19206
|
},
|
|
@@ -18954,6 +19306,7 @@ export class AgentSession {
|
|
|
18954
19306
|
const next = roleModels[nextIndex];
|
|
18955
19307
|
|
|
18956
19308
|
if (options?.temporary) {
|
|
19309
|
+
this.markUserModelSelection();
|
|
18957
19310
|
await this.setModelTemporary(next.model, next.explicitThinkingLevel ? next.thinkingLevel : undefined, {
|
|
18958
19311
|
cause: "temporary-operation",
|
|
18959
19312
|
reason: "temporary-cycle",
|
|
@@ -20603,6 +20956,7 @@ export class AgentSession {
|
|
|
20603
20956
|
onTerminalOverflowNoop?: () => void,
|
|
20604
20957
|
resourceRunId?: string,
|
|
20605
20958
|
ownershipSignal?: AbortSignal,
|
|
20959
|
+
sdkOwnership?: SdkContinuationOwnership,
|
|
20606
20960
|
): Promise<boolean> {
|
|
20607
20961
|
// Safety stops are terminal and must not trigger context maintenance.
|
|
20608
20962
|
if (
|
|
@@ -20657,6 +21011,7 @@ export class AgentSession {
|
|
|
20657
21011
|
generation,
|
|
20658
21012
|
suppressPredecessorAgentEnd: true,
|
|
20659
21013
|
resourceRunId,
|
|
21014
|
+
sdkOwnership,
|
|
20660
21015
|
});
|
|
20661
21016
|
|
|
20662
21017
|
return true;
|
|
@@ -20675,10 +21030,11 @@ export class AgentSession {
|
|
|
20675
21030
|
},
|
|
20676
21031
|
resourceRunId,
|
|
20677
21032
|
signal: ownershipSignal,
|
|
21033
|
+
sdkOwnership,
|
|
20678
21034
|
});
|
|
20679
21035
|
return "continuationScheduled" in status && status.continuationScheduled === true;
|
|
20680
21036
|
}
|
|
20681
|
-
return await this.#scheduleOverflowRetryContinuation(generation, resourceRunId);
|
|
21037
|
+
return await this.#scheduleOverflowRetryContinuation(generation, resourceRunId, sdkOwnership);
|
|
20682
21038
|
}
|
|
20683
21039
|
const compactionSettings = this.settings.getGroup("compaction");
|
|
20684
21040
|
if (!compactionSettings.enabled || compactionSettings.strategy === "off") return false;
|
|
@@ -20724,7 +21080,11 @@ export class AgentSession {
|
|
|
20724
21080
|
const promoted = await this.#tryContextPromotion(assistantMessage, ownershipSignal);
|
|
20725
21081
|
if (ownershipSignal?.aborted) return false;
|
|
20726
21082
|
if (!promoted) {
|
|
20727
|
-
await this.#runAutoCompaction("threshold", false, false, {
|
|
21083
|
+
await this.#runAutoCompaction("threshold", false, false, {
|
|
21084
|
+
resourceRunId,
|
|
21085
|
+
signal: ownershipSignal,
|
|
21086
|
+
sdkOwnership,
|
|
21087
|
+
});
|
|
20728
21088
|
}
|
|
20729
21089
|
}
|
|
20730
21090
|
return true;
|
|
@@ -21078,10 +21438,7 @@ export class AgentSession {
|
|
|
21078
21438
|
const isContextPromoted = this.#temporaryProviderSessionScopes.some(
|
|
21079
21439
|
scope => scope.token.reason === "context-promotion",
|
|
21080
21440
|
);
|
|
21081
|
-
if (
|
|
21082
|
-
!isContextPromoted ||
|
|
21083
|
-
!isDefaultAutoThresholdCeilingApplied(contextWindow, settings)
|
|
21084
|
-
) {
|
|
21441
|
+
if (!isContextPromoted || !isDefaultAutoThresholdCeilingApplied(contextWindow, settings)) {
|
|
21085
21442
|
return settings;
|
|
21086
21443
|
}
|
|
21087
21444
|
|
|
@@ -21490,7 +21847,9 @@ export class AgentSession {
|
|
|
21490
21847
|
// The reminder continues the current prompt, so the predecessor `agent_end`
|
|
21491
21848
|
// must stay held until the continuation turn produces the real terminal.
|
|
21492
21849
|
// Publishing it here would settle the caller's prompt mid-reminder.
|
|
21493
|
-
|
|
21850
|
+
// Disable managed fallback to prevent indefinite retries for this server-initiated turn.
|
|
21851
|
+
this.#todoReminderContinuationGeneration = this.#promptGeneration;
|
|
21852
|
+
this.#scheduleAgentContinue({ skipCompactionCheck: true, suppressPredecessorAgentEnd: true, disableManagedFallback: true });
|
|
21494
21853
|
}
|
|
21495
21854
|
|
|
21496
21855
|
/**
|
|
@@ -21604,6 +21963,11 @@ export class AgentSession {
|
|
|
21604
21963
|
}
|
|
21605
21964
|
}
|
|
21606
21965
|
|
|
21966
|
+
#recordUserCanonicalVariantSelection(): void {
|
|
21967
|
+
this.#userCanonicalVariantSelectionRevision++;
|
|
21968
|
+
this.#userCanonicalVariantSelection = this.#modelRegistry.getSessionCanonicalVariant?.(this.sessionId);
|
|
21969
|
+
}
|
|
21970
|
+
|
|
21607
21971
|
#closeCodexProviderSessionsForHistoryRewrite(): void {
|
|
21608
21972
|
const currentModel = this.model;
|
|
21609
21973
|
if (currentModel?.api !== "openai-codex-responses") return;
|
|
@@ -22207,6 +22571,7 @@ export class AgentSession {
|
|
|
22207
22571
|
signal?: AbortSignal;
|
|
22208
22572
|
beforeTerminalOverflowNoop?: () => void;
|
|
22209
22573
|
resourceRunId?: string;
|
|
22574
|
+
sdkOwnership?: SdkContinuationOwnership;
|
|
22210
22575
|
},
|
|
22211
22576
|
): Promise<AutoCompactionTerminalStatus> {
|
|
22212
22577
|
if (this.#isDisposed || this.#sessionAdmissionClosing) return Promise.resolve({ kind: "skipped" });
|
|
@@ -22227,6 +22592,7 @@ export class AgentSession {
|
|
|
22227
22592
|
signal?: AbortSignal;
|
|
22228
22593
|
beforeTerminalOverflowNoop?: () => void;
|
|
22229
22594
|
resourceRunId?: string;
|
|
22595
|
+
sdkOwnership?: SdkContinuationOwnership;
|
|
22230
22596
|
},
|
|
22231
22597
|
): Promise<AutoCompactionTerminalStatus> {
|
|
22232
22598
|
const compactionSettings = this.settings.getGroup("compaction");
|
|
@@ -22369,7 +22735,14 @@ export class AgentSession {
|
|
|
22369
22735
|
});
|
|
22370
22736
|
if (autoCompactionSignal.aborted) return { kind: "aborted", source: "signal" };
|
|
22371
22737
|
if (continueAfterMaintenance && reason !== "idle" && compactionSettings.autoContinue !== false) {
|
|
22372
|
-
this.#scheduleAutoContinuePrompt(
|
|
22738
|
+
this.#scheduleAutoContinuePrompt(
|
|
22739
|
+
generation,
|
|
22740
|
+
true,
|
|
22741
|
+
options?.resourceRunId,
|
|
22742
|
+
undefined,
|
|
22743
|
+
undefined,
|
|
22744
|
+
options?.sdkOwnership,
|
|
22745
|
+
);
|
|
22373
22746
|
}
|
|
22374
22747
|
|
|
22375
22748
|
if (autoCompactionSignal.aborted) return { kind: "aborted", source: "signal" };
|
|
@@ -22424,7 +22797,11 @@ export class AgentSession {
|
|
|
22424
22797
|
}
|
|
22425
22798
|
const overflowContinuationScheduled =
|
|
22426
22799
|
!overflowNoopWouldReplay && willRetry && !continuationSkipReason
|
|
22427
|
-
? await this.#scheduleOverflowRetryContinuation(
|
|
22800
|
+
? await this.#scheduleOverflowRetryContinuation(
|
|
22801
|
+
generation,
|
|
22802
|
+
options?.resourceRunId,
|
|
22803
|
+
options?.sdkOwnership,
|
|
22804
|
+
)
|
|
22428
22805
|
: false;
|
|
22429
22806
|
await this.#emitSessionEvent({
|
|
22430
22807
|
type: "auto_compaction_end",
|
|
@@ -22474,7 +22851,14 @@ export class AgentSession {
|
|
|
22474
22851
|
resourceRunId: options?.resourceRunId,
|
|
22475
22852
|
});
|
|
22476
22853
|
} else if (continueAfterMaintenance && reason !== "idle" && compactionSettings.autoContinue !== false) {
|
|
22477
|
-
this.#scheduleAutoContinuePrompt(
|
|
22854
|
+
this.#scheduleAutoContinuePrompt(
|
|
22855
|
+
generation,
|
|
22856
|
+
true,
|
|
22857
|
+
options?.resourceRunId,
|
|
22858
|
+
undefined,
|
|
22859
|
+
undefined,
|
|
22860
|
+
options?.sdkOwnership,
|
|
22861
|
+
);
|
|
22478
22862
|
}
|
|
22479
22863
|
return { kind: "skipped" };
|
|
22480
22864
|
}
|
|
@@ -22759,7 +23143,11 @@ export class AgentSession {
|
|
|
22759
23143
|
}
|
|
22760
23144
|
const overflowContinuationScheduled =
|
|
22761
23145
|
willRetry && !continuationSkipReason
|
|
22762
|
-
? await this.#scheduleOverflowRetryContinuation(
|
|
23146
|
+
? await this.#scheduleOverflowRetryContinuation(
|
|
23147
|
+
generation,
|
|
23148
|
+
options?.resourceRunId,
|
|
23149
|
+
options?.sdkOwnership,
|
|
23150
|
+
)
|
|
22763
23151
|
: false;
|
|
22764
23152
|
|
|
22765
23153
|
await this.#emitSessionEvent({
|
|
@@ -22793,7 +23181,14 @@ export class AgentSession {
|
|
|
22793
23181
|
resourceRunId: options?.resourceRunId,
|
|
22794
23182
|
});
|
|
22795
23183
|
} else if (continueAfterMaintenance && reason !== "idle" && compactionSettings.autoContinue !== false) {
|
|
22796
|
-
this.#scheduleAutoContinuePrompt(
|
|
23184
|
+
this.#scheduleAutoContinuePrompt(
|
|
23185
|
+
generation,
|
|
23186
|
+
true,
|
|
23187
|
+
options?.resourceRunId,
|
|
23188
|
+
undefined,
|
|
23189
|
+
undefined,
|
|
23190
|
+
options?.sdkOwnership,
|
|
23191
|
+
);
|
|
22797
23192
|
}
|
|
22798
23193
|
return { kind: "compacted" };
|
|
22799
23194
|
} catch (error) {
|
|
@@ -22986,7 +23381,8 @@ export class AgentSession {
|
|
|
22986
23381
|
isAuthenticated(apiKey) &&
|
|
22987
23382
|
authStorage.getSessionCredentialRowId(model.provider, this.credentialSessionId) === credential.id &&
|
|
22988
23383
|
authStorage.getSessionCredentialType(model.provider, this.credentialSessionId) === credentialKind &&
|
|
22989
|
-
currentCredential &&
|
|
23384
|
+
currentCredential &&
|
|
23385
|
+
!currentCredential.disabled
|
|
22990
23386
|
)
|
|
22991
23387
|
return apiKey;
|
|
22992
23388
|
}
|
|
@@ -22994,6 +23390,7 @@ export class AgentSession {
|
|
|
22994
23390
|
}
|
|
22995
23391
|
|
|
22996
23392
|
#isRetryableError(message: AssistantMessage): boolean {
|
|
23393
|
+
if (isTerminalCodexProviderFailure(message)) return false;
|
|
22997
23394
|
if (this.#isTerminalProviderFirstEventTimeout(message)) return false;
|
|
22998
23395
|
if (message.errorMessage?.startsWith("Model fallback chain exhausted;")) return false;
|
|
22999
23396
|
if (message.errorMessage?.startsWith("Managed fallback retried the escaped non-ASCII")) return false;
|
|
@@ -23004,7 +23401,11 @@ export class AgentSession {
|
|
|
23004
23401
|
return false;
|
|
23005
23402
|
const contextWindow = this.model?.contextWindow ?? 0;
|
|
23006
23403
|
if (classifyContextOverflow(message, transportFailure, contextWindow)) return false;
|
|
23007
|
-
if (
|
|
23404
|
+
if (
|
|
23405
|
+
(isBareDefaultCodexOverload(message) || isBareDefaultCodexProviderFailure(message)) &&
|
|
23406
|
+
this.settings.get("retry.enabled") !== false
|
|
23407
|
+
)
|
|
23408
|
+
return true;
|
|
23008
23409
|
const managedFallback = this.#defaultFallbackChain().chain.entries.length > 1;
|
|
23009
23410
|
// An account-specific model rejection that cannot rotate to another
|
|
23010
23411
|
// credential stays terminal only on the session's own retry path; managed
|
|
@@ -23117,9 +23518,7 @@ export class AgentSession {
|
|
|
23117
23518
|
// Errors that will never succeed on retry (auth/permission, malformed
|
|
23118
23519
|
// request, unknown/unsupported model). These surface immediately rather
|
|
23119
23520
|
// than retry forever.
|
|
23120
|
-
return
|
|
23121
|
-
errorMessage,
|
|
23122
|
-
);
|
|
23521
|
+
return TERMINAL_ERROR_MESSAGE.test(errorMessage);
|
|
23123
23522
|
}
|
|
23124
23523
|
|
|
23125
23524
|
#extractExplicitHttpStatusFromErrorMessage(errorMessage: string): number | undefined {
|
|
@@ -23153,6 +23552,7 @@ export class AgentSession {
|
|
|
23153
23552
|
if (message.errorKind === "local_snapshot_failure") return "local_snapshot";
|
|
23154
23553
|
if (message.errorKind === "local_buffer_overflow") return "local_buffer_overflow";
|
|
23155
23554
|
if (this.#isTypedFirstEventTimeout(message)) return "first_event_timeout";
|
|
23555
|
+
if (message.errorKind === "local_empty_response") return "empty_response";
|
|
23156
23556
|
if (this.#isTypedEmptyResponse(message)) return "empty_response";
|
|
23157
23557
|
if (this.#isCodexCredentialModelUnavailable(message)) {
|
|
23158
23558
|
return this.#canRotateCodexCredential(message) ? "unknown" : "terminal";
|
|
@@ -23407,6 +23807,7 @@ export class AgentSession {
|
|
|
23407
23807
|
}
|
|
23408
23808
|
|
|
23409
23809
|
async #handleManagedAttemptOutcome(outcome: ManagedAttemptOutcome): Promise<ManagedAttemptDecision> {
|
|
23810
|
+
const sdkOwnership = this.#captureSdkContinuationOwnership(outcome.scope);
|
|
23410
23811
|
const attemptAbortEpoch = this.#abortAdmissionEpoch;
|
|
23411
23812
|
const attemptCancelled = () =>
|
|
23412
23813
|
this.#isDisposed || this.#sessionAdmissionClosing || this.#abortAdmissionEpoch !== attemptAbortEpoch;
|
|
@@ -23456,6 +23857,8 @@ export class AgentSession {
|
|
|
23456
23857
|
return {
|
|
23457
23858
|
type: "retry",
|
|
23458
23859
|
continuation: async ownership => {
|
|
23860
|
+
const continuationSdkOwnership =
|
|
23861
|
+
sdkOwnership ?? this.#captureSdkContinuationOwnership(ownership.handle.scope);
|
|
23459
23862
|
const restoreOwnedTransition = async () => {
|
|
23460
23863
|
if (this.#fallbackTransitionGeneration !== transitionGeneration) return;
|
|
23461
23864
|
this.#fallbackTransitionGeneration++;
|
|
@@ -23542,7 +23945,12 @@ export class AgentSession {
|
|
|
23542
23945
|
...this.#managedFallbackPromptOptions(),
|
|
23543
23946
|
transientRecoveryMessage: this.#escapedNonAsciiRecoveryMessage(),
|
|
23544
23947
|
onRunAccepted: (handle: AttemptRunHandle) => {
|
|
23545
|
-
this.#acceptSdkAttemptRun(
|
|
23948
|
+
this.#acceptSdkAttemptRun(
|
|
23949
|
+
handle,
|
|
23950
|
+
continuationSdkOwnership?.token,
|
|
23951
|
+
continuationSdkOwnership?.cohort,
|
|
23952
|
+
continuationSdkOwnership?.scope,
|
|
23953
|
+
);
|
|
23546
23954
|
},
|
|
23547
23955
|
});
|
|
23548
23956
|
if (
|
|
@@ -23581,11 +23989,18 @@ export class AgentSession {
|
|
|
23581
23989
|
type: "retry",
|
|
23582
23990
|
continuation: async ownership => {
|
|
23583
23991
|
if (attemptCancelled() || !ownership.isCurrent() || ownership.lease.signal.aborted) return;
|
|
23992
|
+
const continuationSdkOwnership =
|
|
23993
|
+
sdkOwnership ?? this.#captureSdkContinuationOwnership(ownership.handle.scope);
|
|
23584
23994
|
await this.agent.continue({
|
|
23585
23995
|
...this.#managedFallbackPromptOptions(),
|
|
23586
23996
|
transientRecoveryMessage: this.#escapedNonAsciiRecoveryMessage(),
|
|
23587
23997
|
onRunAccepted: (handle: AttemptRunHandle) => {
|
|
23588
|
-
this.#acceptSdkAttemptRun(
|
|
23998
|
+
this.#acceptSdkAttemptRun(
|
|
23999
|
+
handle,
|
|
24000
|
+
continuationSdkOwnership?.token,
|
|
24001
|
+
continuationSdkOwnership?.cohort,
|
|
24002
|
+
continuationSdkOwnership?.scope,
|
|
24003
|
+
);
|
|
23589
24004
|
},
|
|
23590
24005
|
});
|
|
23591
24006
|
},
|
|
@@ -23600,6 +24015,10 @@ export class AgentSession {
|
|
|
23600
24015
|
type: "maintenance",
|
|
23601
24016
|
continuation: async ownership => {
|
|
23602
24017
|
if (attemptCancelled() || !ownership.isCurrent() || ownership.lease.signal.aborted) return;
|
|
24018
|
+
// A discarded in-loop attempt need not have published turn_start;
|
|
24019
|
+
// the Agent-supplied handle still identifies its accepted SDK cohort.
|
|
24020
|
+
const continuationSdkOwnership =
|
|
24021
|
+
sdkOwnership ?? this.#captureSdkContinuationOwnership(ownership.handle.scope);
|
|
23603
24022
|
const resourceRunId = String(ownership.logicalRunId);
|
|
23604
24023
|
const previousLease = this.#postPromptLeases.get(resourceRunId);
|
|
23605
24024
|
this.#postPromptLeases.set(resourceRunId, ownership.lease);
|
|
@@ -23617,6 +24036,7 @@ export class AgentSession {
|
|
|
23617
24036
|
},
|
|
23618
24037
|
resourceRunId,
|
|
23619
24038
|
ownership.lease.signal,
|
|
24039
|
+
continuationSdkOwnership,
|
|
23620
24040
|
);
|
|
23621
24041
|
if (
|
|
23622
24042
|
terminalized ||
|
|
@@ -23651,12 +24071,14 @@ export class AgentSession {
|
|
|
23651
24071
|
},
|
|
23652
24072
|
};
|
|
23653
24073
|
}
|
|
23654
|
-
//
|
|
23655
|
-
//
|
|
23656
|
-
//
|
|
23657
|
-
//
|
|
23658
|
-
|
|
23659
|
-
|
|
24074
|
+
// Content-free typed statusless overloads are safe for managed retry when
|
|
24075
|
+
// this discarded attempt is clean, even after earlier committed work in
|
|
24076
|
+
// the same prompt. Preserve the committed failure path when this attempt
|
|
24077
|
+
// itself is not replay-safe.
|
|
24078
|
+
if (
|
|
24079
|
+
isStatuslessTypedOverloadFacts(outcome.failure.transportFailure) &&
|
|
24080
|
+
!this.#isRetryScopeClean(outcome.scope)
|
|
24081
|
+
) {
|
|
23660
24082
|
this.#defaultFallbackChain().resetAttemptBudget();
|
|
23661
24083
|
return this.#managedFallbackExhaustionDecision(
|
|
23662
24084
|
outcome.failure.message,
|
|
@@ -23721,6 +24143,10 @@ export class AgentSession {
|
|
|
23721
24143
|
if (classification === "transient" || classification === "first_event_timeout") {
|
|
23722
24144
|
return { class: "server" };
|
|
23723
24145
|
}
|
|
24146
|
+
// A locally promoted empty response is retryable only when the managed
|
|
24147
|
+
// attempt stayed clean; authorize the configured fallback chain without
|
|
24148
|
+
// fabricating provider transport facts for the runtime-owned failure.
|
|
24149
|
+
if (classification === "empty_response") return { class: "server" };
|
|
23724
24150
|
if (classification === "unknown") return { class: "unknown" };
|
|
23725
24151
|
return undefined;
|
|
23726
24152
|
}
|
|
@@ -23900,9 +24326,7 @@ export class AgentSession {
|
|
|
23900
24326
|
!authStorage.isCredentialAvailable(resolvedModel.provider, credential.id)
|
|
23901
24327
|
)
|
|
23902
24328
|
continue;
|
|
23903
|
-
let credentialKeyResult:
|
|
23904
|
-
| { kind: "resolved"; value: string | undefined }
|
|
23905
|
-
| { kind: "aborted" };
|
|
24329
|
+
let credentialKeyResult: { kind: "resolved"; value: string | undefined } | { kind: "aborted" };
|
|
23906
24330
|
try {
|
|
23907
24331
|
credentialKeyResult = await awaitWithCancellation(
|
|
23908
24332
|
this.#modelRegistry.getApiKey(resolvedModel, this.credentialSessionId, {
|
|
@@ -24000,7 +24424,11 @@ export class AgentSession {
|
|
|
24000
24424
|
!transitionStillOwned()
|
|
24001
24425
|
)
|
|
24002
24426
|
return await rollbackCancelled();
|
|
24003
|
-
if (
|
|
24427
|
+
if (
|
|
24428
|
+
selectedCredentialRowId !== undefined &&
|
|
24429
|
+
selectedCredentialKind !== undefined &&
|
|
24430
|
+
this.#restoreManagedFallbackGetApiKey
|
|
24431
|
+
) {
|
|
24004
24432
|
this.#managedFallbackNextCredentialOverride = {
|
|
24005
24433
|
modelKey: canonicalModelKey,
|
|
24006
24434
|
storageProvider: resolveOAuthStorageProvider(resolvedModel.provider),
|
|
@@ -24294,6 +24722,10 @@ export class AgentSession {
|
|
|
24294
24722
|
scope?: AttemptScope,
|
|
24295
24723
|
scopeWasClean = this.#isRetryScopeClean(scope),
|
|
24296
24724
|
): Promise<boolean | ManagedAttemptDecision> {
|
|
24725
|
+
// Capture the SDK owner before the failed attempt retires its active scope.
|
|
24726
|
+
// Retry/continuation terminals must remain attributed to the prompt that
|
|
24727
|
+
// admitted the provider call, even when the retry starts after agent_end.
|
|
24728
|
+
const retrySdkOwnership = this.#captureSdkContinuationOwnership(scope);
|
|
24297
24729
|
const retryAbortEpoch = this.#abortAdmissionEpoch;
|
|
24298
24730
|
const retryCancelled = () =>
|
|
24299
24731
|
this.#isDisposed || this.#sessionAdmissionClosing || this.#abortAdmissionEpoch !== retryAbortEpoch;
|
|
@@ -24308,9 +24740,25 @@ export class AgentSession {
|
|
|
24308
24740
|
const classification = this.#classifyErrorForRetry(message);
|
|
24309
24741
|
const localSnapshot = classification === "local_snapshot";
|
|
24310
24742
|
const localBufferOverflow = classification === "local_buffer_overflow";
|
|
24743
|
+
// Managed outcomes can reach retry handling without the ordinary admission
|
|
24744
|
+
// check. Do not let retained transport facts bypass the same terminal veto.
|
|
24745
|
+
if (isTerminalCodexProviderFailure(message)) {
|
|
24746
|
+
return managedOutcome ? { type: "terminal", terminal: { stopReason: "error", messages: [message] } } : false;
|
|
24747
|
+
}
|
|
24311
24748
|
if (retryCancelled()) {
|
|
24312
24749
|
return managedOutcome ? { type: "terminal", terminal: { stopReason: "cancelled" } } : false;
|
|
24313
24750
|
}
|
|
24751
|
+
if (
|
|
24752
|
+
transportFailure?.status === undefined &&
|
|
24753
|
+
transportFailure?.providerCode === SERVER_OVERLOADED_PROVIDER_CODE &&
|
|
24754
|
+
(transportFailure.openaiErrorCode === undefined ||
|
|
24755
|
+
transportFailure.openaiErrorCode === SERVER_OVERLOADED_PROVIDER_CODE) &&
|
|
24756
|
+
(managedOutcome ? !scopeWasClean : !this.#hasCleanRetryReplaySafety)
|
|
24757
|
+
) {
|
|
24758
|
+
return managedOutcome
|
|
24759
|
+
? { type: "terminal", terminal: { stopReason: "error", messages: [message] } }
|
|
24760
|
+
: false;
|
|
24761
|
+
}
|
|
24314
24762
|
// A local machinery failure must never stay charged against the provider
|
|
24315
24763
|
// fallback budget, no matter which local exit follows (disabled retry,
|
|
24316
24764
|
// visible-content surface, bounded retry, exhaustion, or the immediate
|
|
@@ -24369,6 +24817,8 @@ export class AgentSession {
|
|
|
24369
24817
|
isBareDefaultCodexOverload(message) ||
|
|
24370
24818
|
isBareDefaultAnthropicOverload(message) ||
|
|
24371
24819
|
isBareDefaultOpenAIResponsesOverload(message);
|
|
24820
|
+
const canReplayBareDefaultCodexFailure = isBareDefaultCodexProviderFailure(message);
|
|
24821
|
+
const boundBareDefaultCodexFailure = canReplayBareDefaultCodexFailure && !legacyRetryConfigured;
|
|
24372
24822
|
const canReplayCodexProviderOverload = isBareDefaultCodexOverload(message);
|
|
24373
24823
|
const reportedRetryMaxAttempts = transportFailure?.retryMaxAttempts;
|
|
24374
24824
|
if (reportedRetryMaxAttempts !== undefined) {
|
|
@@ -24412,22 +24862,9 @@ export class AgentSession {
|
|
|
24412
24862
|
const fallbackTrigger = this.#fallbackTriggerFor(message, !managedFallback, transportFailure);
|
|
24413
24863
|
const trigger:
|
|
24414
24864
|
| { class: FallbackTriggerClass; retryAfterMs?: number; authDisposition?: AuthDisposition }
|
|
24415
|
-
| undefined = canReplayCodexProviderOverload
|
|
24416
|
-
|
|
24417
|
-
|
|
24418
|
-
// the code survived transport, this failure reached the session as an
|
|
24419
|
-
// ordinary committed error and surfaced immediately, so mirror that
|
|
24420
|
-
// behavior with the existing exhaustion decision. However, when called from
|
|
24421
|
-
// the agent_end path (managedOutcome=false), we must return false to allow
|
|
24422
|
-
// proper session termination handling.
|
|
24423
|
-
if (managedFallback && isStatuslessTypedOverloadFacts(transportFailure)) {
|
|
24424
|
-
return managedOutcome
|
|
24425
|
-
? this.#managedFallbackExhaustionDecision(
|
|
24426
|
-
message,
|
|
24427
|
-
message.errorMessage || "Model fallback attempt failed",
|
|
24428
|
-
)
|
|
24429
|
-
: false;
|
|
24430
|
-
}
|
|
24865
|
+
| undefined = canReplayCodexProviderOverload || canReplayBareDefaultCodexFailure
|
|
24866
|
+
? { class: "server" }
|
|
24867
|
+
: fallbackTrigger;
|
|
24431
24868
|
if (!trigger) {
|
|
24432
24869
|
return managedOutcome
|
|
24433
24870
|
? this.#managedFallbackExhaustionDecision(message, message.errorMessage || "Model fallback attempt failed")
|
|
@@ -24516,6 +24953,7 @@ export class AgentSession {
|
|
|
24516
24953
|
if (!managedFallback && !legacyRetryConfigured && !canReplayRotatedCredential && !canReplayEmptyResponse) {
|
|
24517
24954
|
if (
|
|
24518
24955
|
(!canReplayProviderOverload &&
|
|
24956
|
+
!canReplayBareDefaultCodexFailure &&
|
|
24519
24957
|
!canReplayUnexpectedSocketClose &&
|
|
24520
24958
|
!this.#isTypedFirstEventTimeout(message) &&
|
|
24521
24959
|
!messageOnlyWatchdogTimeout &&
|
|
@@ -24534,6 +24972,7 @@ export class AgentSession {
|
|
|
24534
24972
|
!managedFallback &&
|
|
24535
24973
|
classification === "transient" &&
|
|
24536
24974
|
!canReplayProviderOverload &&
|
|
24975
|
+
!boundBareDefaultCodexFailure &&
|
|
24537
24976
|
!canReplayUnexpectedSocketClose &&
|
|
24538
24977
|
!this.#isIdleStreamStallErrorMessage(message.errorMessage ?? "");
|
|
24539
24978
|
|
|
@@ -24638,10 +25077,7 @@ export class AgentSession {
|
|
|
24638
25077
|
if (outcome === "exhausted") {
|
|
24639
25078
|
if (managedFallback) {
|
|
24640
25079
|
let errorMessage = this.#fallbackExhaustionError(controller);
|
|
24641
|
-
if (
|
|
24642
|
-
!providerRetryCeilingReached &&
|
|
24643
|
-
(trigger.class === "quota" || trigger.class === "rate_limit")
|
|
24644
|
-
) {
|
|
25080
|
+
if (!providerRetryCeilingReached && (trigger.class === "quota" || trigger.class === "rate_limit")) {
|
|
24645
25081
|
if (!assistantMessageHasVisibleOrToolContent(message)) {
|
|
24646
25082
|
const mark =
|
|
24647
25083
|
quotaCredentialMark ??
|
|
@@ -24686,6 +25122,8 @@ export class AgentSession {
|
|
|
24686
25122
|
: cappedExponentialWithFullJitter(retrySettings.baseDelayMs, retrySettings.maxDelayMs, attemptsUsed);
|
|
24687
25123
|
|
|
24688
25124
|
const retry = async (ownership?: ManagedAttemptContinuationOwnership): Promise<void> => {
|
|
25125
|
+
const continuationSdkOwnership =
|
|
25126
|
+
retrySdkOwnership ?? this.#captureSdkContinuationOwnership(ownership?.handle.scope);
|
|
24689
25127
|
const activePromptHandle = this.activePromptHandle;
|
|
24690
25128
|
const cancellationSignal =
|
|
24691
25129
|
ownership?.domain.signal ??
|
|
@@ -24900,7 +25338,12 @@ export class AgentSession {
|
|
|
24900
25338
|
await this.agent.continue({
|
|
24901
25339
|
...this.#managedFallbackPromptOptions(),
|
|
24902
25340
|
onRunAccepted: (handle: AttemptRunHandle) => {
|
|
24903
|
-
this.#acceptSdkAttemptRun(
|
|
25341
|
+
this.#acceptSdkAttemptRun(
|
|
25342
|
+
handle,
|
|
25343
|
+
continuationSdkOwnership?.token,
|
|
25344
|
+
continuationSdkOwnership?.cohort,
|
|
25345
|
+
continuationSdkOwnership?.scope,
|
|
25346
|
+
);
|
|
24904
25347
|
},
|
|
24905
25348
|
});
|
|
24906
25349
|
return;
|
|
@@ -24928,6 +25371,7 @@ export class AgentSession {
|
|
|
24928
25371
|
allowDuringCancelAndSubmit: true,
|
|
24929
25372
|
suppressPredecessorAgentEnd: resourceRunId !== undefined,
|
|
24930
25373
|
resourceRunId,
|
|
25374
|
+
sdkOwnership: continuationSdkOwnership,
|
|
24931
25375
|
onError: () => this.#failRetryRecovery("Retry continuation failed to start"),
|
|
24932
25376
|
onSkip: () => this.#failRetryRecovery("Retry continuation was superseded"),
|
|
24933
25377
|
});
|
|
@@ -25155,10 +25599,6 @@ export class AgentSession {
|
|
|
25155
25599
|
// Bash Execution
|
|
25156
25600
|
// =========================================================================
|
|
25157
25601
|
|
|
25158
|
-
async #saveBashOriginalArtifact(originalText: string): Promise<BashArtifactSaveResult> {
|
|
25159
|
-
return saveAgentBashOriginalArtifact(this.sessionManager, originalText);
|
|
25160
|
-
}
|
|
25161
|
-
|
|
25162
25602
|
/**
|
|
25163
25603
|
* Execute a bash command.
|
|
25164
25604
|
* Adds result to agent context and session.
|
|
@@ -25173,6 +25613,7 @@ export class AgentSession {
|
|
|
25173
25613
|
onChunk?: (chunk: string) => void,
|
|
25174
25614
|
options?: { excludeFromContext?: boolean; onPersisted?: () => void },
|
|
25175
25615
|
): Promise<BashResult> {
|
|
25616
|
+
const publishArtifact = this.sessionManager.captureArtifactPublication();
|
|
25176
25617
|
const excludeFromContext = options?.excludeFromContext === true;
|
|
25177
25618
|
this.#markRetryReplayUnsafe();
|
|
25178
25619
|
|
|
@@ -25210,7 +25651,7 @@ export class AgentSession {
|
|
|
25210
25651
|
sessionId: this.sessionId,
|
|
25211
25652
|
cwd,
|
|
25212
25653
|
}),
|
|
25213
|
-
onMinimizedSave: originalText =>
|
|
25654
|
+
onMinimizedSave: originalText => saveAgentBashOriginalArtifact(publishArtifact, originalText),
|
|
25214
25655
|
});
|
|
25215
25656
|
|
|
25216
25657
|
this.recordBashResult(command, result, options);
|
|
@@ -25314,9 +25755,18 @@ export class AgentSession {
|
|
|
25314
25755
|
this.#markRetryReplayUnsafe();
|
|
25315
25756
|
const cwd = this.sessionManager.getCwd();
|
|
25316
25757
|
this.assertEvalExecutionAllowed();
|
|
25758
|
+
const sessionFile = this.sessionManager.getSessionFile();
|
|
25759
|
+
const sessionId = sessionFile ? `session:${sessionFile}:cwd:${cwd}` : `cwd:${cwd}`;
|
|
25760
|
+
const kernelOwnerId = this.#evalKernelOwnerId;
|
|
25761
|
+
const kernelMode = this.settings.get("python.kernelMode");
|
|
25762
|
+
const settings = this.settings;
|
|
25317
25763
|
|
|
25318
25764
|
const abortController = new AbortController();
|
|
25319
|
-
const execution = (async (): Promise<PythonResult> => {
|
|
25765
|
+
const execution = Promise.resolve().then(async (): Promise<PythonResult> => {
|
|
25766
|
+
if (abortController.signal.aborted) {
|
|
25767
|
+
throw abortController.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
25768
|
+
}
|
|
25769
|
+
this.assertEvalExecutionAllowed();
|
|
25320
25770
|
if (this.#extensionRunner?.hasHandlers("user_python")) {
|
|
25321
25771
|
const hookResult = await this.#extensionRunner.emitUserPython({
|
|
25322
25772
|
type: "user_python",
|
|
@@ -25324,6 +25774,9 @@ export class AgentSession {
|
|
|
25324
25774
|
excludeFromContext,
|
|
25325
25775
|
cwd,
|
|
25326
25776
|
});
|
|
25777
|
+
if (abortController.signal.aborted) {
|
|
25778
|
+
throw abortController.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
25779
|
+
}
|
|
25327
25780
|
this.assertEvalExecutionAllowed();
|
|
25328
25781
|
if (hookResult?.result) {
|
|
25329
25782
|
this.recordPythonResult(code, hookResult.result, options);
|
|
@@ -25331,15 +25784,12 @@ export class AgentSession {
|
|
|
25331
25784
|
}
|
|
25332
25785
|
}
|
|
25333
25786
|
|
|
25334
|
-
// Use the same session ID as eval's Python backend for kernel sharing
|
|
25335
|
-
const sessionFile = this.sessionManager.getSessionFile();
|
|
25336
|
-
const sessionId = sessionFile ? `session:${sessionFile}:cwd:${cwd}` : `cwd:${cwd}`;
|
|
25337
25787
|
const result = await executePythonCommand(code, {
|
|
25338
25788
|
cwd,
|
|
25339
25789
|
sessionId,
|
|
25340
|
-
kernelOwnerId
|
|
25341
|
-
kernelMode
|
|
25342
|
-
settings
|
|
25790
|
+
kernelOwnerId,
|
|
25791
|
+
kernelMode,
|
|
25792
|
+
settings,
|
|
25343
25793
|
onChunk,
|
|
25344
25794
|
signal: abortController.signal,
|
|
25345
25795
|
});
|
|
@@ -25348,7 +25798,7 @@ export class AgentSession {
|
|
|
25348
25798
|
// must not reopen a closing session to append history.
|
|
25349
25799
|
if (!this.#evalExecutionDisposing) this.recordPythonResult(code, result, options);
|
|
25350
25800
|
return result;
|
|
25351
|
-
})
|
|
25801
|
+
});
|
|
25352
25802
|
return await this.trackEvalExecution(execution, abortController);
|
|
25353
25803
|
}
|
|
25354
25804
|
|