@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
|
@@ -146,6 +146,29 @@ async function loadConfig(agentDir: string, kind: ChatDaemonKind): Promise<ChatD
|
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Consecutive definite-disabled config reads required before a running owner
|
|
151
|
+
* retires. A non-atomic rewrite can briefly expose a truncated file that parses
|
|
152
|
+
* as valid YAML with `notifications.enabled` defaulted off, so one read is not
|
|
153
|
+
* a settled verdict. With the 5 s heartbeat tick this retires within ~10 s.
|
|
154
|
+
*/
|
|
155
|
+
const DISABLED_READS_BEFORE_RETIRE = 2;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* True only when the current config definitely disables this provider:
|
|
159
|
+
* `notifications.enabled: false`, the provider switched off, or a missing
|
|
160
|
+
* config file (the same results that keep a new owner from starting). Read or
|
|
161
|
+
* validation errors (half-written file, incomplete or quarantined provider) are
|
|
162
|
+
* indeterminate and keep the owner serving.
|
|
163
|
+
*/
|
|
164
|
+
async function configDisablesProvider(agentDir: string, kind: ChatDaemonKind): Promise<boolean> {
|
|
165
|
+
try {
|
|
166
|
+
return (await loadConfig(agentDir, kind)) === undefined;
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
149
172
|
function ownerPid(ownerId: string): number | undefined {
|
|
150
173
|
const match = /^(\d+)(?:-|$)/.exec(ownerId);
|
|
151
174
|
const pid = Number(match?.[1]);
|
|
@@ -231,10 +254,24 @@ export async function runChatDaemonInternal(
|
|
|
231
254
|
return;
|
|
232
255
|
}
|
|
233
256
|
await runtime.start();
|
|
257
|
+
let disabledReads = 0;
|
|
258
|
+
const retireIfDisabled = async (): Promise<void> => {
|
|
259
|
+
if (!(await configDisablesProvider(agentDir, kind))) {
|
|
260
|
+
disabledReads = 0;
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (++disabledReads < DISABLED_READS_BEFORE_RETIRE || stopping) return;
|
|
264
|
+
// Same orderly path as an operator stop: stop the transport, let the
|
|
265
|
+
// serve loop exit, and release ownership as stopped in `finally`.
|
|
266
|
+
stopping = true;
|
|
267
|
+
await stopRuntime();
|
|
268
|
+
};
|
|
269
|
+
// The returned promise never rejects; tests await it to drive one tick.
|
|
234
270
|
interval = (deps.setInterval ?? setInterval)(() => {
|
|
235
|
-
|
|
271
|
+
return (async () => {
|
|
236
272
|
try {
|
|
237
273
|
if (!(await renewHeartbeat())) await terminateForLostOwnership();
|
|
274
|
+
else await retireIfDisabled();
|
|
238
275
|
} catch (error) {
|
|
239
276
|
terminalError ??= error;
|
|
240
277
|
stopping = true;
|
|
@@ -141,8 +141,8 @@ export type ChatDaemonAction = "stop" | "reload";
|
|
|
141
141
|
* crashes, recovery, and attachment retirement cannot replay ambiguous work.
|
|
142
142
|
*/
|
|
143
143
|
export const CHAT_DAEMON_GENERATIONS: Readonly<Record<ChatDaemonKind, number>> = {
|
|
144
|
-
discord:
|
|
145
|
-
slack:
|
|
144
|
+
discord: 84,
|
|
145
|
+
slack: 91,
|
|
146
146
|
};
|
|
147
147
|
|
|
148
148
|
export function chatDaemonGeneration(kind: ChatDaemonKind): number {
|
|
@@ -318,6 +318,9 @@ export class ChatDaemonRuntime {
|
|
|
318
318
|
this.#router = new SessionRouter({
|
|
319
319
|
agentDir: input.agentDir,
|
|
320
320
|
observer: true,
|
|
321
|
+
// A lean final answer carries no messageRef, so the raw native copy of a
|
|
322
|
+
// positioned frame has no identity to collapse onto and would post twice.
|
|
323
|
+
positionedNotificationEffects: true,
|
|
321
324
|
correlateFrame,
|
|
322
325
|
deps: {
|
|
323
326
|
...deps.routerDeps,
|
package/src/sdk/bus/index.ts
CHANGED
|
@@ -27,7 +27,13 @@ import * as fs from "node:fs";
|
|
|
27
27
|
import * as os from "node:os";
|
|
28
28
|
import * as path from "node:path";
|
|
29
29
|
import { promisify } from "node:util";
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
type AgentTerminalOwnerContext,
|
|
32
|
+
isNonDispatchedToolEvent,
|
|
33
|
+
type RunCancellationDomain,
|
|
34
|
+
type RunSettlementProof,
|
|
35
|
+
ThinkingLevel,
|
|
36
|
+
} from "@gajae-code/agent-core";
|
|
31
37
|
import type { ImageContent, TextContent, Tool } from "@gajae-code/ai/core";
|
|
32
38
|
import type { NotificationServer as NativeNotificationServer } from "@gajae-code/natives";
|
|
33
39
|
|
|
@@ -105,6 +111,7 @@ import {
|
|
|
105
111
|
canDeliverSdkEvent,
|
|
106
112
|
createSdkSurfaceFactory,
|
|
107
113
|
masterAttestationForEffectiveHost,
|
|
114
|
+
POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY,
|
|
108
115
|
reattestMasterSessionIdentity,
|
|
109
116
|
SESSION_HOST_OBSERVER_CAPABILITY,
|
|
110
117
|
type SessionSdkHost,
|
|
@@ -204,7 +211,6 @@ import {
|
|
|
204
211
|
ASK_SELECTED_ACK_CAPABILITY,
|
|
205
212
|
type EnsureDaemonResult,
|
|
206
213
|
ensureTelegramDaemonRunningDetailed,
|
|
207
|
-
POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY,
|
|
208
214
|
} from "./telegram-daemon";
|
|
209
215
|
|
|
210
216
|
export type {
|
|
@@ -1229,6 +1235,9 @@ export class PresentationArbiter {
|
|
|
1229
1235
|
interface SessionRuntime {
|
|
1230
1236
|
server: NotificationServer;
|
|
1231
1237
|
host: SessionSdkHost;
|
|
1238
|
+
getJoinedPromptCorrelations: (owner: AgentTerminalOwnerContext) => Array<{ commandId: string; turnId: string }>;
|
|
1239
|
+
isPromptRunOwner: (correlation: { commandId: string; turnId: string }, owner: AgentTerminalOwnerContext) => boolean;
|
|
1240
|
+
retireJoinedPromptOwners: () => void;
|
|
1232
1241
|
/** Delivers one ring-positioned event envelope to every attached subscriber
|
|
1233
1242
|
* connection, applying the same capability gate as event replay. */
|
|
1234
1243
|
broadcastEventFrame: (event: SdkFrame) => string[];
|
|
@@ -2618,6 +2627,12 @@ function sdkControlSurface(
|
|
|
2618
2627
|
error: unknown,
|
|
2619
2628
|
) => void | Promise<void> = () => {},
|
|
2620
2629
|
onPromptAcceptFailed: (correlation: { commandId: string; turnId: string }) => void = () => {},
|
|
2630
|
+
onPromptDiverted: (correlation: { commandId: string; turnId: string }) => void,
|
|
2631
|
+
onPromptPromoted: (
|
|
2632
|
+
correlation: { commandId: string; turnId: string },
|
|
2633
|
+
promotion: { startsOwnRun?: boolean; removed?: boolean },
|
|
2634
|
+
handle: string | undefined,
|
|
2635
|
+
) => void,
|
|
2621
2636
|
acceptGateResolution: () => boolean,
|
|
2622
2637
|
trackGateResolution: <T>(resolution: Promise<T>) => Promise<T>,
|
|
2623
2638
|
admitPrompt: (clientRef?: string) => void,
|
|
@@ -3019,6 +3034,7 @@ function sdkControlSurface(
|
|
|
3019
3034
|
admission.accepted();
|
|
3020
3035
|
accepting = false;
|
|
3021
3036
|
accepted = true;
|
|
3037
|
+
if (effectiveDeliverAs !== undefined) onPromptDiverted(correlation);
|
|
3022
3038
|
// #4743: an accepted run owns a durable terminal publication when it
|
|
3023
3039
|
// settles; teardown joins it via this latch (never-accepted preflights
|
|
3024
3040
|
// produce no durable write and stay unjoined by design).
|
|
@@ -3044,7 +3060,14 @@ function sdkControlSurface(
|
|
|
3044
3060
|
...(effectiveDeliverAs ? { deliverAs: effectiveDeliverAs } : {}),
|
|
3045
3061
|
onPreflightAcceptCommit,
|
|
3046
3062
|
onPreflightAccepted,
|
|
3047
|
-
|
|
3063
|
+
onQueuedPromoted: promotion => {
|
|
3064
|
+
admission.hooks.onQueuedPromoted(promotion);
|
|
3065
|
+
onPromptPromoted(correlation, promotion, ctx.getActivePromptHandle());
|
|
3066
|
+
},
|
|
3067
|
+
onDispatchDisposition: disposition => {
|
|
3068
|
+
admission.hooks.onDispatchDisposition(disposition);
|
|
3069
|
+
if (!disposition.startsOwnRun) onPromptDiverted(correlation);
|
|
3070
|
+
},
|
|
3048
3071
|
preflightSignal: preflightController.signal,
|
|
3049
3072
|
...(sdkRunToken ? { sdkRunToken } : {}),
|
|
3050
3073
|
}),
|
|
@@ -3722,8 +3745,8 @@ function sdkControlSurface(
|
|
|
3722
3745
|
return unavailable("model.cycle", "no session model-cycle seam is installed")();
|
|
3723
3746
|
return { changed: (await ctx.cycleModel()) !== undefined };
|
|
3724
3747
|
},
|
|
3725
|
-
setThinking: level => {
|
|
3726
|
-
api.
|
|
3748
|
+
setThinking: async level => {
|
|
3749
|
+
await api.setThinkingLevelForControl(level as ThinkingLevel, false);
|
|
3727
3750
|
return { changed: true };
|
|
3728
3751
|
},
|
|
3729
3752
|
cycleThinking: () => {
|
|
@@ -4290,6 +4313,8 @@ export function createNotificationsExtension(
|
|
|
4290
4313
|
* preflight outside the durable admission path (review thread P2).
|
|
4291
4314
|
*/
|
|
4292
4315
|
terminalAbortSeams?: {
|
|
4316
|
+
getTerminalRunOwnerForEvent?: (event: object) => AgentTerminalOwnerContext | undefined;
|
|
4317
|
+
getRunOwnerDomain?: (handle: string) => RunCancellationDomain | undefined;
|
|
4293
4318
|
getTerminalTurnEpoch: () => number | undefined;
|
|
4294
4319
|
cancelPendingPreflightForTerminalAbort: () => void;
|
|
4295
4320
|
captureTerminalAbortSteeringSnapshot?: () => void;
|
|
@@ -4577,6 +4602,7 @@ export function createNotificationsExtension(
|
|
|
4577
4602
|
if (reason === "session" && requestedRuntime) {
|
|
4578
4603
|
requestedRuntime.inboundFenced = true;
|
|
4579
4604
|
requestedRuntime.stopping = true;
|
|
4605
|
+
requestedRuntime.retireJoinedPromptOwners();
|
|
4580
4606
|
requestedRuntime.abortEphemeralTurns();
|
|
4581
4607
|
}
|
|
4582
4608
|
if (reason === "session" && requestedRuntime) requestedRuntime.stopSessionNameObserver();
|
|
@@ -4845,6 +4871,19 @@ export function createNotificationsExtension(
|
|
|
4845
4871
|
return failLifecycleStartup("failed", "Lifecycle SDK startup requires an agent directory.");
|
|
4846
4872
|
|
|
4847
4873
|
const pendingInteractive = new Map<string, PendingInteractiveAsk>();
|
|
4874
|
+
const queuedRemovalTerminals = new Map<string, Promise<boolean>>();
|
|
4875
|
+
const joinedPromptOwners = new Map<
|
|
4876
|
+
string,
|
|
4877
|
+
{ correlation: { commandId: string; turnId: string }; owner: AgentTerminalOwnerContext }
|
|
4878
|
+
>();
|
|
4879
|
+
const getJoinedPromptCorrelations = (terminalOwner: AgentTerminalOwnerContext) =>
|
|
4880
|
+
[...joinedPromptOwners.values()]
|
|
4881
|
+
.filter(
|
|
4882
|
+
({ owner }) =>
|
|
4883
|
+
owner.resourceRunId === terminalOwner.resourceRunId && owner.domain === terminalOwner.domain,
|
|
4884
|
+
)
|
|
4885
|
+
.map(({ correlation }) => correlation);
|
|
4886
|
+
const retireJoinedPromptOwners = (): void => joinedPromptOwners.clear();
|
|
4848
4887
|
const pendingPromptCorrelations: Array<{ commandId: string; turnId: string }> = [];
|
|
4849
4888
|
const pendingPromptCorrelationsBySdkRunToken = new Map<string, { commandId: string; turnId: string }>();
|
|
4850
4889
|
const workLease = ctx.getSessionWorkLease?.() ?? createSessionWorkLease();
|
|
@@ -5106,6 +5145,8 @@ export function createNotificationsExtension(
|
|
|
5106
5145
|
* up to a hard maximum runtime anchored to acceptance.
|
|
5107
5146
|
*/
|
|
5108
5147
|
deadlineLease: PromptDeadlineLease;
|
|
5148
|
+
deadlineSuspended?: true;
|
|
5149
|
+
sdkRunToken?: string;
|
|
5109
5150
|
deadlineTimer?: Parameters<typeof clearTimeout>[0];
|
|
5110
5151
|
/**
|
|
5111
5152
|
* Identity of the in-flight deadline expiry attempt (set synchronously
|
|
@@ -5314,10 +5355,12 @@ export function createNotificationsExtension(
|
|
|
5314
5355
|
submission.workLease = undefined;
|
|
5315
5356
|
}
|
|
5316
5357
|
promptSubmissions.delete(key);
|
|
5358
|
+
const [commandId, turnId] = key.split(":", 2);
|
|
5317
5359
|
// A fatal closure is transport-level, not a committed semantic terminal: the
|
|
5318
|
-
// durable record stays authoritative, so it must never leave a tombstone
|
|
5360
|
+
// durable record stays authoritative, so it must never leave a tombstone
|
|
5361
|
+
// or release images still retained by an unsettled run. Runtime teardown
|
|
5362
|
+
// releases those reservations even if this delivery record expires.
|
|
5319
5363
|
if (submission.fatal) return;
|
|
5320
|
-
const [commandId, turnId] = key.split(":", 2);
|
|
5321
5364
|
if (!commandId || !turnId) return;
|
|
5322
5365
|
removePendingPromptCorrelation({ commandId, turnId });
|
|
5323
5366
|
addTerminalTombstone(key, submission.connectionId);
|
|
@@ -5664,7 +5707,7 @@ export function createNotificationsExtension(
|
|
|
5664
5707
|
*/
|
|
5665
5708
|
const armPromptDeadline = (key: string, correlation: { commandId: string; turnId: string }) => {
|
|
5666
5709
|
const submission = promptSubmissions.get(key);
|
|
5667
|
-
if (!submission) return;
|
|
5710
|
+
if (!submission || submission.deadlineSuspended) return;
|
|
5668
5711
|
const lease = submission.deadlineLease;
|
|
5669
5712
|
if (submission.deadlineTimer) clearTimeout(submission.deadlineTimer);
|
|
5670
5713
|
submission.deadlineTimer = setTimeout(
|
|
@@ -5772,25 +5815,37 @@ export function createNotificationsExtension(
|
|
|
5772
5815
|
);
|
|
5773
5816
|
};
|
|
5774
5817
|
const emitPromptEvent = (event: AgentSessionEvent) => {
|
|
5775
|
-
if (!runtime
|
|
5818
|
+
if (!runtime) return;
|
|
5776
5819
|
cleanupPromptRecords();
|
|
5777
|
-
const
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5820
|
+
const handle = ctx.getActivePromptHandle();
|
|
5821
|
+
const domain = handle ? terminalAbortSeams?.getRunOwnerDomain?.(handle) : undefined;
|
|
5822
|
+
const correlations = handle && domain ? getJoinedPromptCorrelations({ resourceRunId: handle, domain }) : [];
|
|
5823
|
+
const root = runtime.activePromptCorrelation;
|
|
5824
|
+
if (
|
|
5825
|
+
root &&
|
|
5826
|
+
!correlations.some(
|
|
5827
|
+
correlation => correlation.commandId === root.commandId && correlation.turnId === root.turnId,
|
|
5828
|
+
)
|
|
5829
|
+
)
|
|
5830
|
+
correlations.unshift(root);
|
|
5831
|
+
for (const correlation of correlations) {
|
|
5832
|
+
// Renewal is attributed exactly like the correlated delivery below.
|
|
5833
|
+
renewPromptDeadline(correlation, event);
|
|
5834
|
+
noteToolDispatchBoundary(correlation, event);
|
|
5835
|
+
const submission = promptSubmissions.get(promptSubmissionKey(correlation));
|
|
5836
|
+
if (!submission || submission.abandoned) continue;
|
|
5837
|
+
const frame = {
|
|
5838
|
+
type: "event",
|
|
5839
|
+
kind: event.type,
|
|
5840
|
+
payload: toAgentWireEventPayload(event),
|
|
5841
|
+
...correlation,
|
|
5842
|
+
};
|
|
5843
|
+
if (!submission.acknowledged) {
|
|
5844
|
+
submission.bufferedFrames.push(frame);
|
|
5845
|
+
continue;
|
|
5846
|
+
}
|
|
5847
|
+
deliverCorrelatedFrame(submission, frame);
|
|
5792
5848
|
}
|
|
5793
|
-
deliverCorrelatedFrame(submission, frame);
|
|
5794
5849
|
};
|
|
5795
5850
|
/**
|
|
5796
5851
|
* Status of a registered deadline expiry attempt after an awaited
|
|
@@ -5809,7 +5864,10 @@ export function createNotificationsExtension(
|
|
|
5809
5864
|
submission: PromptSubmission,
|
|
5810
5865
|
attempt: { lease: PromptDeadlineLease; generation: number; selfAbortStarted?: true },
|
|
5811
5866
|
): DeadlineAttemptStatus => {
|
|
5812
|
-
if (promptSubmissions.get(key) !== submission
|
|
5867
|
+
if (promptSubmissions.get(key) !== submission) return "stale";
|
|
5868
|
+
if (!attempt.selfAbortStarted && (submission.deadlineSuspended || submission.deadlineLease !== attempt.lease))
|
|
5869
|
+
return "superseded";
|
|
5870
|
+
if (submission.deadlineLease !== attempt.lease) return "stale";
|
|
5813
5871
|
const lease = submission.deadlineLease;
|
|
5814
5872
|
// A deadline expiry attempt must not be superseded by progress that its
|
|
5815
5873
|
// OWN abort caused. Terminal fencing aborts the running tool, and the
|
|
@@ -6018,6 +6076,7 @@ export function createNotificationsExtension(
|
|
|
6018
6076
|
maxMs: resolveSdkPromptMaxRuntimeMs(settings?.get("sdk.promptMaxRuntimeMs")),
|
|
6019
6077
|
}),
|
|
6020
6078
|
phase: "active",
|
|
6079
|
+
...(sdkRunToken ? { sdkRunToken } : {}),
|
|
6021
6080
|
...(workLeaseHandle ? { workLease: workLeaseHandle } : {}),
|
|
6022
6081
|
// Bound to the Agent run at `agent_start`; acceptance precedes execution.
|
|
6023
6082
|
executionHandle: undefined,
|
|
@@ -6123,12 +6182,75 @@ export function createNotificationsExtension(
|
|
|
6123
6182
|
correlation: { commandId: string; turnId: string },
|
|
6124
6183
|
handle: string | undefined,
|
|
6125
6184
|
) => {
|
|
6126
|
-
const
|
|
6185
|
+
const key = promptSubmissionKey(correlation);
|
|
6186
|
+
const submission = promptSubmissions.get(key);
|
|
6127
6187
|
if (submission) {
|
|
6188
|
+
if (submission.deadlineSuspended) {
|
|
6189
|
+
submission.deadlineSuspended = undefined;
|
|
6190
|
+
submission.deadlineLease = createPromptDeadlineLease({
|
|
6191
|
+
now: Date.now(),
|
|
6192
|
+
leaseMs: submission.deadlineLease.leaseMs,
|
|
6193
|
+
maxMs: submission.deadlineLease.maxMs,
|
|
6194
|
+
});
|
|
6195
|
+
armPromptDeadline(key, correlation);
|
|
6196
|
+
}
|
|
6128
6197
|
submission.executionHandle = handle;
|
|
6129
6198
|
submission.preflightAbort = undefined;
|
|
6130
6199
|
}
|
|
6131
6200
|
};
|
|
6201
|
+
const onPromptDiverted = (correlation: { commandId: string; turnId: string }) => {
|
|
6202
|
+
const submission = promptSubmissions.get(promptSubmissionKey(correlation));
|
|
6203
|
+
// A follow-up's private token can only be adopted by its exact future run.
|
|
6204
|
+
// Implicit steering has no such future-run authority and must leave pending.
|
|
6205
|
+
if (!submission?.sdkRunToken) removePendingPromptCorrelation(correlation);
|
|
6206
|
+
if (!submission || submission.terminal) return;
|
|
6207
|
+
submission.deadlineSuspended = true;
|
|
6208
|
+
if (submission.deadlineTimer) clearTimeout(submission.deadlineTimer);
|
|
6209
|
+
submission.deadlineTimer = undefined;
|
|
6210
|
+
};
|
|
6211
|
+
const onPromptPromoted = (
|
|
6212
|
+
correlation: { commandId: string; turnId: string },
|
|
6213
|
+
promotion: { startsOwnRun?: boolean; removed?: boolean },
|
|
6214
|
+
handle: string | undefined,
|
|
6215
|
+
) => {
|
|
6216
|
+
const key = promptSubmissionKey(correlation);
|
|
6217
|
+
removePendingPromptCorrelation(correlation);
|
|
6218
|
+
if (promotion.removed) {
|
|
6219
|
+
const completion: { terminalized?: boolean } = {};
|
|
6220
|
+
const removal = terminalizePrompt(
|
|
6221
|
+
correlation,
|
|
6222
|
+
{ kind: "stopped", reason: "cancelled", provenance: "client_cancel" },
|
|
6223
|
+
{},
|
|
6224
|
+
undefined,
|
|
6225
|
+
completion,
|
|
6226
|
+
).then(() => completion.terminalized === true);
|
|
6227
|
+
queuedRemovalTerminals.set(key, removal);
|
|
6228
|
+
trackReconciliationProducer(
|
|
6229
|
+
removal.finally(() => {
|
|
6230
|
+
if (queuedRemovalTerminals.get(key) === removal) queuedRemovalTerminals.delete(key);
|
|
6231
|
+
}),
|
|
6232
|
+
);
|
|
6233
|
+
return;
|
|
6234
|
+
}
|
|
6235
|
+
const submission = promptSubmissions.get(key);
|
|
6236
|
+
if (!submission || submission.terminal) return;
|
|
6237
|
+
submission.deadlineSuspended = undefined;
|
|
6238
|
+
submission.deadlineLease = createPromptDeadlineLease({
|
|
6239
|
+
now: Date.now(),
|
|
6240
|
+
leaseMs: submission.deadlineLease.leaseMs,
|
|
6241
|
+
maxMs: submission.deadlineLease.maxMs,
|
|
6242
|
+
});
|
|
6243
|
+
armPromptDeadline(key, correlation);
|
|
6244
|
+
if (promotion.startsOwnRun === true) {
|
|
6245
|
+
if (submission.sdkRunToken) pendingPromptCorrelationsBySdkRunToken.set(submission.sdkRunToken, correlation);
|
|
6246
|
+
else pendingPromptCorrelations.push(correlation);
|
|
6247
|
+
} else {
|
|
6248
|
+
bindPromptExecutionHandle(correlation, handle);
|
|
6249
|
+
const domain = handle ? terminalAbortSeams?.getRunOwnerDomain?.(handle) : undefined;
|
|
6250
|
+
if (handle && domain)
|
|
6251
|
+
joinedPromptOwners.set(key, { correlation, owner: { resourceRunId: handle, domain } });
|
|
6252
|
+
}
|
|
6253
|
+
};
|
|
6132
6254
|
const terminalizePrompt = async (
|
|
6133
6255
|
correlation: { commandId: string; turnId: string },
|
|
6134
6256
|
requestedOutcome: SdkPromptTerminalOutcome,
|
|
@@ -6156,6 +6278,7 @@ export function createNotificationsExtension(
|
|
|
6156
6278
|
// the seam must refuse to fence the successor's lineage (review
|
|
6157
6279
|
// thread P1).
|
|
6158
6280
|
const terminalExpectedEpoch = options.terminal ? terminalAbortSeams?.getTerminalTurnEpoch?.() : undefined;
|
|
6281
|
+
const deadlineAttempt = submission.deadlineAttempt;
|
|
6159
6282
|
let winner: SdkPromptTerminalOutcome;
|
|
6160
6283
|
try {
|
|
6161
6284
|
winner = await kindReconciliation.claimPendingOutcome(
|
|
@@ -6179,7 +6302,6 @@ export function createNotificationsExtension(
|
|
|
6179
6302
|
// attempt must then back off — reset to active and reschedule —
|
|
6180
6303
|
// instead of fencing and publishing a deadline terminal for a live
|
|
6181
6304
|
// prompt. A re-accepted or evicted submission is never touched.
|
|
6182
|
-
const deadlineAttempt = submission.deadlineAttempt;
|
|
6183
6305
|
if (deadlineAttempt) {
|
|
6184
6306
|
const key = promptSubmissionKey(correlation);
|
|
6185
6307
|
const status = deadlineAttemptStatus(key, submission, deadlineAttempt);
|
|
@@ -6366,6 +6488,7 @@ export function createNotificationsExtension(
|
|
|
6366
6488
|
}
|
|
6367
6489
|
if (submission.deadlineTimer) clearTimeout(submission.deadlineTimer);
|
|
6368
6490
|
if (!recordPromptTerminal(correlation)) return;
|
|
6491
|
+
joinedPromptOwners.delete(promptSubmissionKey(correlation));
|
|
6369
6492
|
if (!runtime) {
|
|
6370
6493
|
// The runtime (and with it the positioned ring) is gone, so the
|
|
6371
6494
|
// terminal can never be published from this process; expire the
|
|
@@ -6547,6 +6670,8 @@ export function createNotificationsExtension(
|
|
|
6547
6670
|
recordPromptAccepted,
|
|
6548
6671
|
recordPromptFailure,
|
|
6549
6672
|
discardPromptAcceptance,
|
|
6673
|
+
onPromptDiverted,
|
|
6674
|
+
onPromptPromoted,
|
|
6550
6675
|
() => runtime?.stopping !== true,
|
|
6551
6676
|
trackGateResolution,
|
|
6552
6677
|
admitPromptSubmission,
|
|
@@ -6599,9 +6724,15 @@ export function createNotificationsExtension(
|
|
|
6599
6724
|
return { aborted: true, disposition: "cancelled" as const };
|
|
6600
6725
|
}
|
|
6601
6726
|
}
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6727
|
+
const removal = queuedRemovalTerminals.get(key);
|
|
6728
|
+
if (removal) {
|
|
6729
|
+
if (!(await removal))
|
|
6730
|
+
throw new TypedControlError("busy", "Queued prompt cancellation could not be durably confirmed.");
|
|
6731
|
+
} else {
|
|
6732
|
+
await terminalizePrompt({ commandId, turnId }, cancellationOutcome, {
|
|
6733
|
+
fence: hasExecutionHandle || !submission.preflightAbort,
|
|
6734
|
+
});
|
|
6735
|
+
}
|
|
6605
6736
|
}
|
|
6606
6737
|
return { aborted: true, disposition: "cancelled" as const };
|
|
6607
6738
|
},
|
|
@@ -7107,6 +7238,20 @@ export function createNotificationsExtension(
|
|
|
7107
7238
|
);
|
|
7108
7239
|
return already_terminalResult;
|
|
7109
7240
|
}
|
|
7241
|
+
if (currentSubmission.preflightAbort) {
|
|
7242
|
+
try {
|
|
7243
|
+
await currentSubmission.preflightAbort();
|
|
7244
|
+
} catch (error) {
|
|
7245
|
+
logger.warn(`sdk: accepted queued cancellation failed: ${String(error)}`);
|
|
7246
|
+
failPromptClosed(
|
|
7247
|
+
{ commandId, turnId },
|
|
7248
|
+
currentSubmission,
|
|
7249
|
+
"terminal_uncertain",
|
|
7250
|
+
"Accepted queued prompt could not be settled before cancellation.",
|
|
7251
|
+
);
|
|
7252
|
+
return { ok: false as const, reason: "worker_unsettled" as const };
|
|
7253
|
+
}
|
|
7254
|
+
}
|
|
7110
7255
|
if (preflightCancel?.hasPending()) {
|
|
7111
7256
|
preflightCancel.cancel();
|
|
7112
7257
|
// The seam cancels the SESSION-WIDE preflight controller:
|
|
@@ -7115,11 +7260,30 @@ export function createNotificationsExtension(
|
|
|
7115
7260
|
if (noOtherConnectionPreflights?.() !== false)
|
|
7116
7261
|
terminalAbortSeams?.cancelPendingPreflightForTerminalAbort?.();
|
|
7117
7262
|
}
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7263
|
+
const removal = queuedRemovalTerminals.get(promptSubmissionKey({ commandId, turnId }));
|
|
7264
|
+
const completion: { terminalized?: boolean } = {};
|
|
7265
|
+
if (removal) completion.terminalized = await removal;
|
|
7266
|
+
else
|
|
7267
|
+
await terminalizePrompt(
|
|
7268
|
+
{ commandId, turnId },
|
|
7269
|
+
{ kind: "stopped", reason: "cancelled", provenance: "client_cancel" },
|
|
7270
|
+
{ fence: Boolean(currentSubmission.executionHandle) },
|
|
7271
|
+
undefined,
|
|
7272
|
+
completion,
|
|
7273
|
+
);
|
|
7274
|
+
const durable = kindReconciliation.lookupResult(currentSubmission.reconciliationKind, {
|
|
7275
|
+
commandId,
|
|
7276
|
+
turnId,
|
|
7277
|
+
});
|
|
7278
|
+
if (
|
|
7279
|
+
completion.terminalized !== true &&
|
|
7280
|
+
(durable.terminalAt === undefined ||
|
|
7281
|
+
(durable.status !== "terminal_ok" && durable.status !== "failed"))
|
|
7282
|
+
) {
|
|
7283
|
+
// The reserved marker remains uncertain; never commit deterministic no-effect
|
|
7284
|
+
// authority while the accepted submission still lacks a durable terminal.
|
|
7285
|
+
return { ok: false as const, reason: "worker_unsettled" as const };
|
|
7286
|
+
}
|
|
7123
7287
|
// No prompt won the race: finalize the reserved row so a later
|
|
7124
7288
|
// same-key retry replays this deterministic no_active_turn result
|
|
7125
7289
|
// instead of reservation uncertainty (review thread P2).
|
|
@@ -7993,6 +8157,12 @@ export function createNotificationsExtension(
|
|
|
7993
8157
|
runtime = {
|
|
7994
8158
|
server,
|
|
7995
8159
|
host,
|
|
8160
|
+
getJoinedPromptCorrelations,
|
|
8161
|
+
isPromptRunOwner: (correlation, owner) => {
|
|
8162
|
+
const handle = promptSubmissions.get(promptSubmissionKey(correlation))?.executionHandle;
|
|
8163
|
+
return handle === owner.resourceRunId && terminalAbortSeams?.getRunOwnerDomain?.(handle) === owner.domain;
|
|
8164
|
+
},
|
|
8165
|
+
retireJoinedPromptOwners,
|
|
7996
8166
|
broadcastEventFrame,
|
|
7997
8167
|
broadcastEventFrameWithReceipts,
|
|
7998
8168
|
revisions,
|
|
@@ -9896,13 +10066,25 @@ export function createNotificationsExtension(
|
|
|
9896
10066
|
const id = sessionId(ctx);
|
|
9897
10067
|
const rt = runtimes.get(id);
|
|
9898
10068
|
if (!rt) return;
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
rt.
|
|
9904
|
-
|
|
9905
|
-
|
|
10069
|
+
// The Agent's terminal owner is independent of delivery correlation. Never
|
|
10070
|
+
// borrow a successor's run handle to settle a predecessor's SDK prompts.
|
|
10071
|
+
const terminalOwner = terminalAbortSeams?.getTerminalRunOwnerForEvent?.(event);
|
|
10072
|
+
const rootCorrelation = rt.activePromptCorrelation;
|
|
10073
|
+
const correlations = terminalOwner ? rt.getJoinedPromptCorrelations(terminalOwner) : [];
|
|
10074
|
+
if (
|
|
10075
|
+
rootCorrelation &&
|
|
10076
|
+
(!terminalOwner || rt.isPromptRunOwner(rootCorrelation, terminalOwner)) &&
|
|
10077
|
+
!correlations.some(
|
|
10078
|
+
correlation =>
|
|
10079
|
+
correlation.commandId === rootCorrelation.commandId && correlation.turnId === rootCorrelation.turnId,
|
|
10080
|
+
)
|
|
10081
|
+
)
|
|
10082
|
+
correlations.unshift(rootCorrelation);
|
|
10083
|
+
for (const correlation of correlations) {
|
|
10084
|
+
// This attributed agent_end is an execution boundary even when the
|
|
10085
|
+
// subsequent durable terminal claim fails. A fatal transport closure
|
|
10086
|
+
// clears attribution, so an unrelated later agent_end cannot settle a
|
|
10087
|
+
// predecessor's prompt correlation.
|
|
9906
10088
|
const assistants = (Array.isArray(event.messages) ? [...event.messages].reverse() : []).filter(
|
|
9907
10089
|
message => message && typeof message === "object" && (message as { role?: unknown }).role === "assistant",
|
|
9908
10090
|
) as Array<{ stopReason?: unknown; errorKind?: unknown; errorCode?: unknown }>;
|
|
@@ -9990,11 +10172,24 @@ export function createNotificationsExtension(
|
|
|
9990
10172
|
}
|
|
9991
10173
|
: {}),
|
|
9992
10174
|
});
|
|
9993
|
-
} else {
|
|
9994
|
-
rt.emitPromptLifecycle(undefined, { type: "agent_end", sessionId: id });
|
|
9995
10175
|
}
|
|
10176
|
+
if (correlations.length === 0) rt.emitPromptLifecycle(undefined, { type: "agent_end", sessionId: id });
|
|
10177
|
+
if (
|
|
10178
|
+
rootCorrelation &&
|
|
10179
|
+
terminalOwner &&
|
|
10180
|
+
!rt.isPromptRunOwner(rootCorrelation, terminalOwner) &&
|
|
10181
|
+
!correlations.some(
|
|
10182
|
+
correlation =>
|
|
10183
|
+
correlation.commandId === rootCorrelation.commandId && correlation.turnId === rootCorrelation.turnId,
|
|
10184
|
+
)
|
|
10185
|
+
)
|
|
10186
|
+
return;
|
|
10187
|
+
rt.busy = false;
|
|
10188
|
+
void rt.host
|
|
10189
|
+
.reportActivity("idle")
|
|
10190
|
+
.catch(error => logger.warn(`notifications: idle activity checkpoint failed: ${String(error)}`));
|
|
9996
10191
|
finishAgentWork(rt, event.stopReason === "paused");
|
|
9997
|
-
rt.activePromptCorrelation = undefined;
|
|
10192
|
+
if (rt.activePromptCorrelation === rootCorrelation) rt.activePromptCorrelation = undefined;
|
|
9998
10193
|
terminalizeInFlightTools(rt, id, event.stopReason === "cancelled" ? "cancelled" : "failed");
|
|
9999
10194
|
try {
|
|
10000
10195
|
pushSessionFrame(rt, { type: "activity", sessionId: id, state: "idle" });
|
|
@@ -296,8 +296,13 @@ export const SDK_LIFECYCLE_ROUTER_PROTOCOL_VERSION = 1;
|
|
|
296
296
|
* so generation-191 owners cannot reap hosts with queued or promoted work.
|
|
297
297
|
* Generation 193 gates streamed content on negotiated observer capabilities,
|
|
298
298
|
* so existing owners are replaced before exposing the new observer path.
|
|
299
|
+
* Generation 201 binds queued cancellation and terminal deadlines to the exact
|
|
300
|
+
* consuming run, so pre-fix owners cannot serve the new generic lifecycle path.
|
|
301
|
+
* Generation 202 joins queued-removal terminal publication before ordinary
|
|
302
|
+
* abort acknowledgement, replacing owners that still acknowledge cancellation
|
|
303
|
+
* before its terminal record is durable.
|
|
299
304
|
*/
|
|
300
|
-
export const DAEMON_GENERATION =
|
|
305
|
+
export const DAEMON_GENERATION = 202;
|
|
301
306
|
|
|
302
307
|
/**
|
|
303
308
|
* Serving-compatibility boundary for daemon lifecycle requests. Epoch 7
|
|
@@ -71,6 +71,7 @@ export {
|
|
|
71
71
|
TELEGRAM_TRANSPORT_GENERATION,
|
|
72
72
|
} from "./telegram-daemon-contract";
|
|
73
73
|
|
|
74
|
+
import { POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY } from "../host/host";
|
|
74
75
|
import {
|
|
75
76
|
type AgentDirSessionLifecycleService,
|
|
76
77
|
createSessionLifecycleService,
|
|
@@ -303,8 +304,9 @@ export const ASK_CONTROLS_CAPABILITY = "ask_controls_v1";
|
|
|
303
304
|
export const TOOL_ACTIVITY_CAPABILITY = "tool_activity_v2";
|
|
304
305
|
/** Receive-only compatibility capability for pre-v2 hosts. */
|
|
305
306
|
export const LEGACY_TOOL_ACTIVITY_CAPABILITY = "tool_activity_v1";
|
|
306
|
-
/**
|
|
307
|
-
export
|
|
307
|
+
/** Public `sdk/bus/telegram-daemon` path for the canonical `sdk/host` capability token. */
|
|
308
|
+
export { POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY };
|
|
309
|
+
|
|
308
310
|
type ToolActivityCapability = "v1" | "v2";
|
|
309
311
|
|
|
310
312
|
function negotiateToolActivityCapability(
|
|
@@ -167,6 +167,8 @@ export function sdkPublicFailure(code: string, details?: unknown, proof?: Public
|
|
|
167
167
|
const kinds: Record<string, PublicFailureKind> = {
|
|
168
168
|
usage: "usage",
|
|
169
169
|
invalid_input: "usage",
|
|
170
|
+
unknown_operation: "usage",
|
|
171
|
+
not_a_repository: "usage",
|
|
170
172
|
invalid_json: "invalid_json",
|
|
171
173
|
broker_unavailable: "broker_unavailable",
|
|
172
174
|
session_unavailable: "endpoint_stale",
|
|
@@ -177,6 +179,7 @@ export function sdkPublicFailure(code: string, details?: unknown, proof?: Public
|
|
|
177
179
|
tail_timeout: "timeout",
|
|
178
180
|
wait_timeout: "wait_timeout",
|
|
179
181
|
uncertain_after_send: "uncertain_after_send",
|
|
182
|
+
busy: "busy",
|
|
180
183
|
authorization_denied: "authorization_denied",
|
|
181
184
|
unauthorized: "authorization_denied",
|
|
182
185
|
forbidden: "authorization_denied",
|
|
@@ -203,8 +206,15 @@ export function sdkPublicFailure(code: string, details?: unknown, proof?: Public
|
|
|
203
206
|
references,
|
|
204
207
|
// A typed `resource_gone` keeps its public classification; the fixed
|
|
205
208
|
// diagnostic only separates absent resource state from an empty result.
|
|
206
|
-
// It asserts no cause and echoes no host-supplied text.
|
|
207
|
-
|
|
209
|
+
// It asserts no cause and echoes no host-supplied text. The usage-mapped
|
|
210
|
+
// codes likewise attach fixed guidance instead of the original message.
|
|
211
|
+
...(code === "resource_gone"
|
|
212
|
+
? { diagnostics: ["sdk_resource_gone" as const] }
|
|
213
|
+
: code === "unknown_operation"
|
|
214
|
+
? { diagnostics: ["sdk_unknown_operation" as const] }
|
|
215
|
+
: code === "not_a_repository"
|
|
216
|
+
? { diagnostics: ["sdk_scope_requires_repository" as const] }
|
|
217
|
+
: {}),
|
|
208
218
|
});
|
|
209
219
|
}
|
|
210
220
|
|
|
@@ -1248,7 +1258,11 @@ async function runSend(agentDir: string, sessionId: string, args: SdkSessionCliA
|
|
|
1248
1258
|
? ("wait_timeout" as const)
|
|
1249
1259
|
: failure.input.kind,
|
|
1250
1260
|
}
|
|
1251
|
-
:
|
|
1261
|
+
: failure.input.kind === "busy"
|
|
1262
|
+
? // turn.prompt is refused while a turn runs and its admission is released
|
|
1263
|
+
// before any execution, so the prompt definitively did not apply.
|
|
1264
|
+
{ proof: "pre-effect" as const }
|
|
1265
|
+
: {}),
|
|
1252
1266
|
references: failure.input.references,
|
|
1253
1267
|
});
|
|
1254
1268
|
}
|