@gajae-code/coding-agent 0.16.7 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +180 -1
- package/dist/types/capability/fs.d.ts +37 -4
- package/dist/types/capability/index.d.ts +19 -0
- package/dist/types/capability/types.d.ts +9 -0
- package/dist/types/cli/doctor/args.d.ts +36 -0
- package/dist/types/cli/doctor/checks.d.ts +18 -0
- package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
- package/dist/types/cli/doctor/context.d.ts +89 -0
- package/dist/types/cli/doctor/files.d.ts +27 -0
- package/dist/types/cli/doctor/ids.d.ts +20 -0
- package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
- package/dist/types/cli/doctor/journal.d.ts +43 -0
- package/dist/types/cli/doctor/managed-link.d.ts +39 -0
- package/dist/types/cli/doctor/native-probe.d.ts +2 -0
- package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
- package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
- package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
- package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
- package/dist/types/cli/doctor/probe-client.d.ts +9 -0
- package/dist/types/cli/doctor/probe-types.d.ts +18 -0
- package/dist/types/cli/doctor/probe.d.ts +3 -0
- package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
- package/dist/types/cli/doctor/repairs.d.ts +28 -0
- package/dist/types/cli/doctor/report.d.ts +27 -0
- package/dist/types/cli/doctor/runner.d.ts +4 -0
- package/dist/types/cli/doctor/safety.d.ts +10 -0
- package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
- package/dist/types/cli/doctor/service-targets.d.ts +41 -0
- package/dist/types/cli/doctor/types.d.ts +145 -0
- package/dist/types/cli/doctor-cli.d.ts +7 -0
- package/dist/types/cli/doctor-supervisor.d.ts +121 -0
- package/dist/types/cli/doctor-worker.d.ts +29 -0
- package/dist/types/cli/install-activation.d.ts +158 -0
- package/dist/types/cli/macos-community-app.d.ts +41 -0
- package/dist/types/cli/mcp-cli.d.ts +0 -11
- package/dist/types/cli/update-cli.d.ts +41 -4
- package/dist/types/cli-main.d.ts +174 -0
- package/dist/types/cli.d.ts +1 -171
- package/dist/types/commands/doctor.d.ts +7 -0
- package/dist/types/commands/sdk.d.ts +17 -8
- package/dist/types/config/autorouting-tier-map.d.ts +19 -0
- package/dist/types/config/file-lock.d.ts +27 -3
- package/dist/types/config/model-preset-registry.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +12 -5
- package/dist/types/config/model-resolver.d.ts +16 -3
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
- package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
- package/dist/types/cursor.d.ts +9 -9
- package/dist/types/discovery/agents-md.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +36 -7
- package/dist/types/discovery/index.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +22 -1
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/plugins/manager.d.ts +33 -4
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
- package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
- package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
- package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
- package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
- package/dist/types/main.d.ts +19 -1
- package/dist/types/modes/acp/acp-agent.d.ts +40 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
- package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -2
- package/dist/types/sdk/acp/adapter.d.ts +5 -1
- package/dist/types/sdk/broker/broker.d.ts +51 -0
- package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
- package/dist/types/sdk/broker/discovery.d.ts +38 -0
- package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
- package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
- package/dist/types/sdk/broker/runtime.d.ts +26 -0
- package/dist/types/sdk/broker/session-index.d.ts +13 -4
- package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
- package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
- package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
- package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
- package/dist/types/sdk/bus/index.d.ts +2 -0
- package/dist/types/sdk/bus/notification-service.d.ts +3 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
- package/dist/types/sdk/cli/session-cli.d.ts +1 -0
- package/dist/types/sdk/host/session-runtime.d.ts +4 -0
- package/dist/types/sdk/host/surface-policy.d.ts +3 -1
- package/dist/types/sdk/lifecycle/service.d.ts +44 -10
- package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
- package/dist/types/sdk/prompt-failure.d.ts +47 -0
- package/dist/types/sdk/prompt-status.d.ts +19 -0
- package/dist/types/sdk/router/session-router.d.ts +3 -4
- package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
- package/dist/types/sdk/session-authority.d.ts +9 -0
- package/dist/types/sdk/session.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +1 -1
- package/dist/types/session/fallback-chain-controller.d.ts +3 -6
- package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
- package/dist/types/session/primary-control-surface.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +6 -0
- package/dist/types/tools/ask.d.ts +25 -0
- package/dist/types/tools/image-gen.d.ts +0 -4
- package/dist/types/tools/skill-discovery.d.ts +7 -5
- package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
- package/dist/types/utils/changelog.d.ts +0 -9
- package/dist/types/utils/mupdf-wasm.d.ts +1 -0
- package/package.json +9 -8
- package/scripts/compile-args.ts +8 -4
- package/src/capability/fs.ts +395 -17
- package/src/capability/index.ts +273 -10
- package/src/capability/types.ts +9 -0
- package/src/cli/customize-doctor.ts +18 -12
- package/src/cli/doctor/args.ts +236 -0
- package/src/cli/doctor/checks.ts +431 -0
- package/src/cli/doctor/config-repairs.ts +517 -0
- package/src/cli/doctor/context.ts +149 -0
- package/src/cli/doctor/files.ts +149 -0
- package/src/cli/doctor/ids.ts +115 -0
- package/src/cli/doctor/install-repairs.ts +335 -0
- package/src/cli/doctor/journal.ts +423 -0
- package/src/cli/doctor/managed-link.ts +514 -0
- package/src/cli/doctor/native-probe.ts +13 -0
- package/src/cli/doctor/permission-repairs.ts +242 -0
- package/src/cli/doctor/plugin-quarantine.ts +377 -0
- package/src/cli/doctor/plugin-restore.ts +59 -0
- package/src/cli/doctor/plugin-targets.ts +373 -0
- package/src/cli/doctor/probe-client.ts +195 -0
- package/src/cli/doctor/probe-types.ts +21 -0
- package/src/cli/doctor/probe.ts +42 -0
- package/src/cli/doctor/projection-probe.ts +249 -0
- package/src/cli/doctor/repairs.ts +1157 -0
- package/src/cli/doctor/report.ts +176 -0
- package/src/cli/doctor/runner.ts +342 -0
- package/src/cli/doctor/safety.ts +40 -0
- package/src/cli/doctor/service-repairs.ts +452 -0
- package/src/cli/doctor/service-targets.ts +274 -0
- package/src/cli/doctor/types.ts +164 -0
- package/src/cli/doctor-cli.ts +62 -0
- package/src/cli/doctor-supervisor.ts +571 -0
- package/src/cli/doctor-worker.ts +181 -0
- package/src/cli/install-activation.ts +666 -0
- package/src/cli/macos-community-app.ts +1449 -0
- package/src/cli/mcp-cli.ts +11 -21
- package/src/cli/nofile-limit.ts +5 -1
- package/src/cli/plugin-cli.ts +6 -1
- package/src/cli/update-cli.ts +362 -264
- package/src/cli-main.ts +517 -0
- package/src/cli.ts +64 -433
- package/src/commands/autoresearch.ts +11 -5
- package/src/commands/completion.ts +1 -1
- package/src/commands/doctor.ts +13 -0
- package/src/commands/sdk.ts +58 -10
- package/src/commands/ultragoal.ts +11 -5
- package/src/config/autorouting-tier-map.ts +7 -0
- package/src/config/file-lock.ts +736 -71
- package/src/config/mcp-schema.json +3 -3
- package/src/config/model-preset-registry.ts +1 -0
- package/src/config/model-registry.ts +80 -27
- package/src/config/model-resolver.ts +33 -4
- package/src/config/models-config-schema.ts +2 -0
- package/src/config/settings-schema.ts +6 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -0
- package/src/coordinator-mcp/server.ts +534 -51
- package/src/coordinator-mcp/session-reaper.ts +64 -8
- package/src/cursor.ts +223 -53
- package/src/discovery/agents-md.ts +74 -8
- package/src/discovery/agents.ts +32 -7
- package/src/discovery/builtin.ts +184 -75
- package/src/discovery/claude-plugins.ts +85 -17
- package/src/discovery/cline.ts +38 -10
- package/src/discovery/cursor.ts +19 -6
- package/src/discovery/gemini.ts +62 -22
- package/src/discovery/github.ts +13 -3
- package/src/discovery/helpers.ts +483 -89
- package/src/discovery/index.ts +1 -0
- package/src/discovery/mcp-json.ts +36 -10
- package/src/discovery/opencode.ts +36 -19
- package/src/discovery/ssh.ts +11 -8
- package/src/discovery/windsurf.ts +12 -3
- package/src/exec/bash-executor.ts +10 -3
- package/src/exec/isolated-shell.ts +15 -2
- package/src/extensibility/extensions/loader.ts +88 -26
- package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
- package/src/extensibility/gjc-plugins/paths.ts +4 -1
- package/src/extensibility/gjc-plugins/types.ts +27 -0
- package/src/extensibility/plugins/manager.ts +200 -22
- package/src/extensibility/plugins/marketplace/cache.ts +55 -2
- package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
- package/src/extensibility/plugins/marketplace/registry.ts +153 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
- package/src/extensibility/runtime-skill-discovery.ts +61 -9
- package/src/extensibility/skill-management.ts +7 -1
- package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
- package/src/gjc-runtime/launch-worktree.test.ts +248 -0
- package/src/gjc-runtime/launch-worktree.ts +275 -38
- package/src/gjc-runtime/repository-binding.ts +26 -1
- package/src/gjc-runtime/session-layout.ts +10 -0
- package/src/gjc-runtime/session-state-lock.ts +330 -23
- package/src/gjc-runtime/session-state-sidecar.ts +328 -80
- package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +28 -26
- package/src/main.ts +150 -29
- package/src/memories/index.ts +24 -2
- package/src/modes/acp/acp-agent.ts +522 -68
- package/src/modes/components/agent-dashboard.ts +3 -1
- package/src/modes/components/model-selector.ts +28 -19
- package/src/modes/components/plugin-settings.ts +2 -1
- package/src/modes/controllers/selector-controller.ts +15 -9
- package/src/modes/interactive-mode.ts +21 -3
- package/src/prompts/system/system-prompt.md +5 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/move-session.md +4 -0
- package/src/prompts/tools/read.md +2 -1
- package/src/prompts/tools/skill-discovery.md +6 -5
- package/src/prompts/tools/task.md +1 -0
- package/src/runtime-mcp/config-writer.ts +228 -0
- package/src/runtime-mcp/oauth-discovery.ts +114 -14
- package/src/runtime-mcp/policy-json-edit.ts +129 -0
- package/src/runtime-mcp/startup-policy.ts +14 -0
- package/src/runtime-mcp/types.ts +2 -2
- package/src/sdk/acp/adapter.ts +27 -12
- package/src/sdk/broker/broker.ts +273 -44
- package/src/sdk/broker/daemon-entry.ts +119 -0
- package/src/sdk/broker/discovery.ts +173 -20
- package/src/sdk/broker/doctor-restart.ts +206 -0
- package/src/sdk/broker/endpoint-authority.ts +36 -0
- package/src/sdk/broker/ensure.ts +49 -14
- package/src/sdk/broker/lifecycle.ts +174 -42
- package/src/sdk/broker/process-incarnation.ts +86 -2
- package/src/sdk/broker/runtime.ts +145 -21
- package/src/sdk/broker/session-index.ts +136 -22
- package/src/sdk/broker/spawn-substrate.ts +4 -1
- package/src/sdk/broker/transport.ts +5 -0
- package/src/sdk/broker/worktree-occupancy.ts +21 -1
- package/src/sdk/bus/chat-daemon-cli.ts +63 -0
- package/src/sdk/bus/chat-daemon-control.ts +260 -64
- package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
- package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
- package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
- package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
- package/src/sdk/bus/index.ts +252 -51
- package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
- package/src/sdk/bus/notification-service.ts +21 -3
- package/src/sdk/bus/reconciliation-store.ts +17 -11
- package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/bus/telegram-daemon-control.ts +47 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
- package/src/sdk/bus/telegram-daemon.ts +178 -13
- package/src/sdk/cli/session-cli.ts +100 -12
- package/src/sdk/host/host.ts +2 -7
- package/src/sdk/host/session-runtime.test.ts +329 -8
- package/src/sdk/host/session-runtime.ts +202 -50
- package/src/sdk/host/surface-policy.ts +8 -1
- package/src/sdk/lifecycle/service.ts +199 -22
- package/src/sdk/mcp/server.ts +1 -1
- package/src/sdk/prompt-deadline-lease.ts +12 -4
- package/src/sdk/prompt-deadline-manager.ts +5 -7
- package/src/sdk/prompt-failure.ts +148 -0
- package/src/sdk/prompt-status.ts +30 -1
- package/src/sdk/prompt-watchdog.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +18 -0
- package/src/sdk/protocol/operation-registry.ts +20 -8
- package/src/sdk/router/session-router.ts +8 -3
- package/src/sdk/service-artifact-paths.ts +26 -0
- package/src/sdk/session-authority.ts +10 -0
- package/src/sdk/session.ts +361 -194
- package/src/session/agent-session.ts +398 -93
- package/src/session/blob-store.ts +9 -9
- package/src/session/fallback-chain-controller.ts +3 -7
- package/src/session/internal/managed-session-scope.ts +445 -29
- package/src/session/internal/managed-session-storage.ts +38 -6
- package/src/session/primary-control-surface.ts +12 -0
- package/src/session/session-manager.ts +11 -3
- package/src/session/session-storage.ts +1 -1
- package/src/session-import/codex.ts +6 -1
- package/src/session-import/redact.ts +7 -0
- package/src/skill-state/workflow-mutation-guard.ts +645 -39
- package/src/slash-commands/builtin-registry.ts +7 -3
- package/src/system-prompt.ts +8 -0
- package/src/task/executor.ts +36 -3
- package/src/task/types.ts +27 -5
- package/src/tools/ask.ts +114 -34
- package/src/tools/browser/actions.ts +2 -2
- package/src/tools/browser/tab-worker.ts +11 -8
- package/src/tools/descriptors.ts +6 -1
- package/src/tools/fetch.ts +7 -2
- package/src/tools/image-gen.ts +33 -34
- package/src/tools/read.ts +78 -32
- package/src/tools/skill-discovery.ts +17 -7
- package/src/tools/tool-catalog.generated.ts +8 -8
- package/src/tools/ultragoal-ask-guard.ts +16 -26
- package/src/utils/changelog.ts +7 -1
- package/src/utils/git.ts +3 -1
- package/src/utils/markit.ts +24 -2
- package/src/utils/mupdf-wasm.ts +26 -0
- package/src/web/search/providers/openai-compatible.ts +191 -14
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type DoctorDaemonOwner = "telegram" | "discord" | "slack";
|
|
2
|
+
|
|
3
|
+
export interface DoctorDaemonIdentity {
|
|
4
|
+
owner: DoctorDaemonOwner;
|
|
5
|
+
ownerId: string;
|
|
6
|
+
generation: number;
|
|
7
|
+
incarnation: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DoctorDaemonOccupancy {
|
|
11
|
+
attached: number;
|
|
12
|
+
inflight: number;
|
|
13
|
+
inbound: number;
|
|
14
|
+
outbound: number;
|
|
15
|
+
cleanup: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const DOCTOR_DAEMON_OCCUPANCY_KEYS = ["attached", "inflight", "inbound", "outbound", "cleanup"] as const;
|
|
19
|
+
|
|
20
|
+
export interface DoctorDaemonStatus extends DoctorDaemonIdentity {
|
|
21
|
+
requestId: string;
|
|
22
|
+
phase: "idle" | "prepared" | "committed" | "cancelled" | "expired";
|
|
23
|
+
admitting: boolean;
|
|
24
|
+
occupancy: DoctorDaemonOccupancy;
|
|
25
|
+
leaseExpiresAt: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface DoctorDaemonControlRequest extends DoctorDaemonIdentity {
|
|
29
|
+
version: 1;
|
|
30
|
+
requestId: string;
|
|
31
|
+
action: "prepare" | "commit" | "cancel" | "status";
|
|
32
|
+
createdAt: number;
|
|
33
|
+
leaseExpiresAt?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function doctorDaemonOccupancyEmpty(): DoctorDaemonOccupancy {
|
|
37
|
+
return { attached: 0, inflight: 0, inbound: 0, outbound: 0, cleanup: 0 };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* True only when every named occupancy category is an explicit, valid,
|
|
42
|
+
* zero-valued integer. An empty object, a partial object, or an object with
|
|
43
|
+
* extra/malformed keys is never vacuously "settled" — `Object.values({}).
|
|
44
|
+
* every(...)` was previously `true` for `{}` because there is nothing to
|
|
45
|
+
* iterate; this checks the exact required key set instead.
|
|
46
|
+
*/
|
|
47
|
+
export function doctorDaemonOccupancySettled(occupancy: DoctorDaemonOccupancy | undefined): boolean {
|
|
48
|
+
if (!occupancy || typeof occupancy !== "object") return false;
|
|
49
|
+
if (Object.keys(occupancy).length !== DOCTOR_DAEMON_OCCUPANCY_KEYS.length) return false;
|
|
50
|
+
return DOCTOR_DAEMON_OCCUPANCY_KEYS.every(key => {
|
|
51
|
+
const value = occupancy[key];
|
|
52
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value === 0;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function doctorDaemonIdentityMatches(
|
|
57
|
+
left: DoctorDaemonIdentity | undefined,
|
|
58
|
+
right: DoctorDaemonIdentity,
|
|
59
|
+
): boolean {
|
|
60
|
+
return (
|
|
61
|
+
left?.owner === right.owner &&
|
|
62
|
+
left?.ownerId === right.ownerId &&
|
|
63
|
+
left?.generation === right.generation &&
|
|
64
|
+
left?.incarnation === right.incarnation
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function isDoctorDaemonControlRequest(value: unknown): value is DoctorDaemonControlRequest {
|
|
69
|
+
if (!value || typeof value !== "object") return false;
|
|
70
|
+
const candidate = value as Record<string, unknown>;
|
|
71
|
+
return (
|
|
72
|
+
candidate.version === 1 &&
|
|
73
|
+
typeof candidate.requestId === "string" &&
|
|
74
|
+
candidate.requestId.length > 0 &&
|
|
75
|
+
(candidate.action === "prepare" ||
|
|
76
|
+
candidate.action === "commit" ||
|
|
77
|
+
candidate.action === "cancel" ||
|
|
78
|
+
candidate.action === "status") &&
|
|
79
|
+
(candidate.owner === "telegram" || candidate.owner === "discord" || candidate.owner === "slack") &&
|
|
80
|
+
typeof candidate.ownerId === "string" &&
|
|
81
|
+
candidate.ownerId.length > 0 &&
|
|
82
|
+
typeof candidate.generation === "number" &&
|
|
83
|
+
Number.isSafeInteger(candidate.generation) &&
|
|
84
|
+
candidate.generation >= 0 &&
|
|
85
|
+
typeof candidate.incarnation === "string" &&
|
|
86
|
+
candidate.incarnation.length > 0 &&
|
|
87
|
+
typeof candidate.createdAt === "number" &&
|
|
88
|
+
Number.isFinite(candidate.createdAt) &&
|
|
89
|
+
(candidate.leaseExpiresAt === undefined ||
|
|
90
|
+
(typeof candidate.leaseExpiresAt === "number" && Number.isFinite(candidate.leaseExpiresAt)))
|
|
91
|
+
);
|
|
92
|
+
}
|
package/src/sdk/bus/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ 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 { type RunSettlementProof, ThinkingLevel } from "@gajae-code/agent-core";
|
|
30
|
+
import { isNonDispatchedToolEvent, type RunSettlementProof, ThinkingLevel } from "@gajae-code/agent-core";
|
|
31
31
|
import type { ImageContent, TextContent, Tool } from "@gajae-code/ai/core";
|
|
32
32
|
import type { NotificationServer as NativeNotificationServer } from "@gajae-code/natives";
|
|
33
33
|
|
|
@@ -90,7 +90,7 @@ import { acpFinalTextFromMessage } from "../acp/final-text";
|
|
|
90
90
|
import { ensureBroker } from "../broker/ensure";
|
|
91
91
|
import { publishSessionHostRuntimeEvidence, type SessionHostRuntimePublication } from "../broker/lifecycle";
|
|
92
92
|
import { processIncarnation } from "../broker/process-incarnation";
|
|
93
|
-
import { resolveSessionLocator, SessionIndex } from "../broker/session-index";
|
|
93
|
+
import { resolveSessionLocator, SessionIndex, type SessionIndexEvent } from "../broker/session-index";
|
|
94
94
|
import {
|
|
95
95
|
CAP_GATED_FRAME_KINDS,
|
|
96
96
|
createSdkSurfaceFactory,
|
|
@@ -114,7 +114,19 @@ import {
|
|
|
114
114
|
syntheticModelInputError,
|
|
115
115
|
syntheticNamespaceCollision,
|
|
116
116
|
} from "../model-profile-model";
|
|
117
|
-
import {
|
|
117
|
+
import {
|
|
118
|
+
createPromptDeadlineLease,
|
|
119
|
+
isAttributableProgressEventType,
|
|
120
|
+
type PromptDeadlineLease,
|
|
121
|
+
promptDeadlineAt,
|
|
122
|
+
recordAttributableProgress,
|
|
123
|
+
} from "../prompt-deadline-lease";
|
|
124
|
+
import {
|
|
125
|
+
assistantFailureCode,
|
|
126
|
+
failedPromptOutcome,
|
|
127
|
+
formatPromptFailureForLocalLog,
|
|
128
|
+
sanitizePromptFailure,
|
|
129
|
+
} from "../prompt-failure";
|
|
118
130
|
import { PROMPT_CLIENT_REF_MAX_LENGTH, type SdkPromptTerminalOutcome } from "../prompt-status";
|
|
119
131
|
import { OPERATIONS } from "../protocol/operation-registry";
|
|
120
132
|
import {
|
|
@@ -2389,6 +2401,7 @@ function sdkQuerySurface(
|
|
|
2389
2401
|
status: "unknown",
|
|
2390
2402
|
}),
|
|
2391
2403
|
getRuntimeHost: () => SessionSdkHost | undefined = () => undefined,
|
|
2404
|
+
primaryControlSurface: "cli" | "sdk" = "sdk",
|
|
2392
2405
|
): SessionSurface {
|
|
2393
2406
|
return createSdkSurfaceFactory({
|
|
2394
2407
|
ctx,
|
|
@@ -2402,6 +2415,7 @@ function sdkQuerySurface(
|
|
|
2402
2415
|
steerStatusLookup,
|
|
2403
2416
|
hostTools: () => getInstalledDefinitions("host_tools") !== undefined,
|
|
2404
2417
|
getRuntimeHost,
|
|
2418
|
+
primaryControlSurface,
|
|
2405
2419
|
}).query;
|
|
2406
2420
|
}
|
|
2407
2421
|
|
|
@@ -4052,6 +4066,8 @@ export function createNotificationsExtension(
|
|
|
4052
4066
|
controller?: NotificationSessionController;
|
|
4053
4067
|
/** Whether this host mode can own the root SDK endpoint. Default: true. */
|
|
4054
4068
|
sdkHostModeSupported?: boolean;
|
|
4069
|
+
/** Startup surface that owns host-level permission and lifecycle authority. */
|
|
4070
|
+
primaryControlSurface?: "cli" | "sdk";
|
|
4055
4071
|
/** In-memory master capability for private broker verification only. */
|
|
4056
4072
|
masterCapability?: string;
|
|
4057
4073
|
/** Opaque direct-role epoch this effective host may adopt. */
|
|
@@ -4775,8 +4791,22 @@ export function createNotificationsExtension(
|
|
|
4775
4791
|
/** Fatal/uncertain closure: transport-level only, never a semantic terminal. */
|
|
4776
4792
|
fatal?: boolean;
|
|
4777
4793
|
createdAt: number;
|
|
4778
|
-
|
|
4794
|
+
/**
|
|
4795
|
+
* Bounded progress-aware terminal deadline: the inactivity window renews
|
|
4796
|
+
* on attributable tool progress correlated to this exact accepted prompt,
|
|
4797
|
+
* up to a hard maximum runtime anchored to acceptance.
|
|
4798
|
+
*/
|
|
4799
|
+
deadlineLease: PromptDeadlineLease;
|
|
4779
4800
|
deadlineTimer?: Parameters<typeof clearTimeout>[0];
|
|
4801
|
+
/**
|
|
4802
|
+
* Identity of the in-flight deadline expiry attempt (set synchronously
|
|
4803
|
+
* by the firing deadline timer, cleared when the attempt completes or
|
|
4804
|
+
* is superseded). Fresh attributable progress recorded while the
|
|
4805
|
+
* attempt awaits durable reconciliation advances the lease generation;
|
|
4806
|
+
* the attempt must then back off instead of terminalizing a live prompt
|
|
4807
|
+
* (mirrors PromptDeadlineManager).
|
|
4808
|
+
*/
|
|
4809
|
+
deadlineAttempt?: { lease: PromptDeadlineLease; generation: number };
|
|
4780
4810
|
phase: "active" | "outcome_claimed" | "terminalizing" | "publication_closed" | "delivered";
|
|
4781
4811
|
outcome?: SdkPromptTerminalOutcome;
|
|
4782
4812
|
/** Agent-owned resource run captured at acceptance; cleanup targets only this handle. */
|
|
@@ -4991,10 +5021,59 @@ export function createNotificationsExtension(
|
|
|
4991
5021
|
finalizePrompt(key, correlation);
|
|
4992
5022
|
}
|
|
4993
5023
|
};
|
|
5024
|
+
const readFiniteSetting = (key: "sdk.promptDeadlineMs" | "sdk.promptMaxRuntimeMs", fallback: number): number => {
|
|
5025
|
+
const value = settings?.get(key);
|
|
5026
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
5027
|
+
};
|
|
5028
|
+
/**
|
|
5029
|
+
* (Re)arm the accepted prompt's terminal deadline from its current lease.
|
|
5030
|
+
* `terminalizePrompt` stays the single authoritative terminal owner; this
|
|
5031
|
+
* only decides when it is invoked.
|
|
5032
|
+
*/
|
|
5033
|
+
const armPromptDeadline = (key: string, correlation: { commandId: string; turnId: string }) => {
|
|
5034
|
+
const submission = promptSubmissions.get(key);
|
|
5035
|
+
if (!submission) return;
|
|
5036
|
+
const lease = submission.deadlineLease;
|
|
5037
|
+
if (submission.deadlineTimer) clearTimeout(submission.deadlineTimer);
|
|
5038
|
+
submission.deadlineTimer = setTimeout(
|
|
5039
|
+
() => {
|
|
5040
|
+
const current = promptSubmissions.get(key);
|
|
5041
|
+
// Identity fencing: a discarded, evicted or re-accepted submission is
|
|
5042
|
+
// never terminalized by a predecessor's timer.
|
|
5043
|
+
if (!current || current.deadlineLease !== lease) return;
|
|
5044
|
+
// Progress delivered while this timer was pending renews the lease, so
|
|
5045
|
+
// re-arm instead of terminalizing a demonstrably live prompt.
|
|
5046
|
+
if (Date.now() < promptDeadlineAt(lease)) {
|
|
5047
|
+
armPromptDeadline(key, correlation);
|
|
5048
|
+
return;
|
|
5049
|
+
}
|
|
5050
|
+
// Register the expiry attempt BEFORE the awaited durable claim:
|
|
5051
|
+
// progress arriving while the claim is in flight must supersede
|
|
5052
|
+
// this attempt (see the post-claim fence in terminalizePrompt).
|
|
5053
|
+
current.deadlineAttempt = { lease, generation: lease.generation };
|
|
5054
|
+
void terminalizePrompt(
|
|
5055
|
+
correlation,
|
|
5056
|
+
{
|
|
5057
|
+
kind: "failed",
|
|
5058
|
+
code: "prompt_deadline_exceeded",
|
|
5059
|
+
message: "Prompt deadline exceeded.",
|
|
5060
|
+
provenance: "deadline",
|
|
5061
|
+
phase: "submission",
|
|
5062
|
+
category: "deadline",
|
|
5063
|
+
},
|
|
5064
|
+
{ fence: true },
|
|
5065
|
+
{ diagnostic: { reason: "Prompt deadline exceeded." } },
|
|
5066
|
+
);
|
|
5067
|
+
},
|
|
5068
|
+
Math.max(0, promptDeadlineAt(lease) - Date.now()),
|
|
5069
|
+
);
|
|
5070
|
+
};
|
|
4994
5071
|
const emitPromptEvent = (event: AgentSessionEvent) => {
|
|
4995
5072
|
if (!runtime?.activePromptCorrelation) return;
|
|
4996
5073
|
cleanupPromptRecords();
|
|
4997
5074
|
const correlation = runtime.activePromptCorrelation;
|
|
5075
|
+
// Renewal is attributed exactly like the correlated delivery below.
|
|
5076
|
+
renewPromptDeadline(correlation, event);
|
|
4998
5077
|
const submission = promptSubmissions.get(promptSubmissionKey(correlation));
|
|
4999
5078
|
if (!submission || submission.abandoned) return;
|
|
5000
5079
|
const frame = {
|
|
@@ -5014,6 +5093,59 @@ export function createNotificationsExtension(
|
|
|
5014
5093
|
abandonPrompt(submission);
|
|
5015
5094
|
}
|
|
5016
5095
|
};
|
|
5096
|
+
/**
|
|
5097
|
+
* Status of a registered deadline expiry attempt after an awaited
|
|
5098
|
+
* reconciliation transition (mirrors PromptDeadlineManager).
|
|
5099
|
+
* - "current": no superseding progress; the attempt may proceed.
|
|
5100
|
+
* - "superseded": fresh attributable progress renewed the lease past now.
|
|
5101
|
+
* The hard cap needs no special case: promptDeadlineAt is the minimum
|
|
5102
|
+
* of the renewed window and acceptedAt+maxMs, so progress at an
|
|
5103
|
+
* already-due cap still reads expired and the attempt proceeds.
|
|
5104
|
+
* - "stale": the submission was cleared, evicted or re-accepted under
|
|
5105
|
+
* this attempt; it must touch nothing.
|
|
5106
|
+
*/
|
|
5107
|
+
type DeadlineAttemptStatus = "current" | "superseded" | "stale";
|
|
5108
|
+
const deadlineAttemptStatus = (
|
|
5109
|
+
key: string,
|
|
5110
|
+
submission: PromptSubmission,
|
|
5111
|
+
attempt: { lease: PromptDeadlineLease; generation: number },
|
|
5112
|
+
): DeadlineAttemptStatus => {
|
|
5113
|
+
if (promptSubmissions.get(key) !== submission || submission.deadlineLease !== attempt.lease) return "stale";
|
|
5114
|
+
const lease = submission.deadlineLease;
|
|
5115
|
+
if (lease.generation !== attempt.generation && Date.now() < promptDeadlineAt(lease)) return "superseded";
|
|
5116
|
+
return "current";
|
|
5117
|
+
};
|
|
5118
|
+
/**
|
|
5119
|
+
* Renew the accepted prompt's deadline on attributable progress. The
|
|
5120
|
+
* allowlist stays owned by the shared lease module, so streaming chatter,
|
|
5121
|
+
* tool updates, heartbeats and retry bookkeeping never renew. Pairing-only
|
|
5122
|
+
* synthetic tool pairs (never dispatched, marked via the dispatch-identity
|
|
5123
|
+
* side channel rather than the wire) never renew either: they prove
|
|
5124
|
+
* pairing, not progress. Only a pre-terminal submission may re-arm behind
|
|
5125
|
+
* its terminal owner; progress arriving while a deadline expiry attempt
|
|
5126
|
+
* awaits durable reconciliation is recorded (advancing the attempt fence)
|
|
5127
|
+
* but never re-arms — the attempt itself reschedules on supersession.
|
|
5128
|
+
*/
|
|
5129
|
+
const renewPromptDeadline = (correlation: { commandId: string; turnId: string }, event: { type: string }) => {
|
|
5130
|
+
if (!isAttributableProgressEventType(event.type) || isNonDispatchedToolEvent(event)) return;
|
|
5131
|
+
const key = promptSubmissionKey(correlation);
|
|
5132
|
+
const submission = promptSubmissions.get(key);
|
|
5133
|
+
if (!submission) return;
|
|
5134
|
+
if (
|
|
5135
|
+
submission.deadlineAttempt &&
|
|
5136
|
+
submission.deadlineLease === submission.deadlineAttempt.lease &&
|
|
5137
|
+
(submission.phase === "outcome_claimed" || submission.phase === "terminalizing")
|
|
5138
|
+
) {
|
|
5139
|
+
recordAttributableProgress(submission.deadlineLease, Date.now());
|
|
5140
|
+
return;
|
|
5141
|
+
}
|
|
5142
|
+
if (submission.terminal || submission.phase !== "active") return;
|
|
5143
|
+
const generation = submission.deadlineLease.generation;
|
|
5144
|
+
recordAttributableProgress(submission.deadlineLease, Date.now());
|
|
5145
|
+
// Monotonic: stale or out-of-order progress never moves the lease.
|
|
5146
|
+
if (submission.deadlineLease.generation === generation) return;
|
|
5147
|
+
armPromptDeadline(key, correlation);
|
|
5148
|
+
};
|
|
5017
5149
|
const flushPromptLifecycle = (key: string, submission: PromptSubmission) => {
|
|
5018
5150
|
for (const frame of submission.bufferedFrames.splice(0)) {
|
|
5019
5151
|
try {
|
|
@@ -5073,7 +5205,11 @@ export function createNotificationsExtension(
|
|
|
5073
5205
|
terminal: false,
|
|
5074
5206
|
retainCorrelation: trackReconciliation,
|
|
5075
5207
|
createdAt: Date.now(),
|
|
5076
|
-
|
|
5208
|
+
deadlineLease: createPromptDeadlineLease({
|
|
5209
|
+
now: Date.now(),
|
|
5210
|
+
leaseMs: readFiniteSetting("sdk.promptDeadlineMs", 1_800_000),
|
|
5211
|
+
maxMs: readFiniteSetting("sdk.promptMaxRuntimeMs", 21_600_000),
|
|
5212
|
+
}),
|
|
5077
5213
|
phase: "active",
|
|
5078
5214
|
// Bound to the Agent run at `agent_start`; acceptance precedes execution.
|
|
5079
5215
|
executionHandle: undefined,
|
|
@@ -5081,21 +5217,12 @@ export function createNotificationsExtension(
|
|
|
5081
5217
|
reconciliationKind,
|
|
5082
5218
|
bufferedFrames: [],
|
|
5083
5219
|
};
|
|
5084
|
-
|
|
5220
|
+
const key = promptSubmissionKey(correlation);
|
|
5221
|
+
promptSubmissions.set(key, submission);
|
|
5085
5222
|
if (trackReconciliation) await notePromptReconciliationAccepted(correlation, clientRef);
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
{
|
|
5090
|
-
kind: "failed",
|
|
5091
|
-
code: "prompt_deadline_exceeded",
|
|
5092
|
-
message: "Prompt deadline exceeded.",
|
|
5093
|
-
provenance: "deadline",
|
|
5094
|
-
},
|
|
5095
|
-
{ fence: true },
|
|
5096
|
-
{ diagnostic: { reason: "Prompt deadline exceeded." } },
|
|
5097
|
-
);
|
|
5098
|
-
}, submission.deadlineMs);
|
|
5223
|
+
// Armed only after the durable accept: a rolled-back acceptance
|
|
5224
|
+
// (`discardPromptAcceptance`) must leave no deadline behind.
|
|
5225
|
+
if (promptSubmissions.get(key) === submission) armPromptDeadline(key, correlation);
|
|
5099
5226
|
};
|
|
5100
5227
|
/** Roll back process-local registration when durable acceptance failed. */
|
|
5101
5228
|
const discardPromptAcceptance = (correlation: { commandId: string; turnId: string }) => {
|
|
@@ -5123,6 +5250,7 @@ export function createNotificationsExtension(
|
|
|
5123
5250
|
code: string,
|
|
5124
5251
|
message: string,
|
|
5125
5252
|
) => {
|
|
5253
|
+
submission.deadlineAttempt = undefined;
|
|
5126
5254
|
if (submission.deadlineTimer) clearTimeout(submission.deadlineTimer);
|
|
5127
5255
|
if (!submission.terminal) {
|
|
5128
5256
|
submission.terminal = true;
|
|
@@ -5220,10 +5348,29 @@ export function createNotificationsExtension(
|
|
|
5220
5348
|
// The claim is the durability boundary: without it nothing may be published
|
|
5221
5349
|
// and the endpoint must fail closed so the client rejects exactly once. The
|
|
5222
5350
|
// last durable record stays active for restart recovery.
|
|
5351
|
+
submission.deadlineAttempt = undefined;
|
|
5223
5352
|
logger.warn(`sdk: prompt claim persistence failed: ${String(error)}`);
|
|
5224
5353
|
failPromptClosed(correlation, submission, "terminal_uncertain", "Prompt reconciliation is unavailable.");
|
|
5225
5354
|
return;
|
|
5226
5355
|
}
|
|
5356
|
+
// Deadline-attempt fence across the awaited claim (mirrors
|
|
5357
|
+
// PromptDeadlineManager): fresh attributable progress recorded while
|
|
5358
|
+
// the claim was in flight advances the lease generation. The pending
|
|
5359
|
+
// attempt must then back off — reset to active and reschedule —
|
|
5360
|
+
// instead of fencing and publishing a deadline terminal for a live
|
|
5361
|
+
// prompt. A re-accepted or evicted submission is never touched.
|
|
5362
|
+
const deadlineAttempt = submission.deadlineAttempt;
|
|
5363
|
+
if (deadlineAttempt) {
|
|
5364
|
+
const key = promptSubmissionKey(correlation);
|
|
5365
|
+
const status = deadlineAttemptStatus(key, submission, deadlineAttempt);
|
|
5366
|
+
if (status === "stale") return;
|
|
5367
|
+
if (status === "superseded") {
|
|
5368
|
+
submission.deadlineAttempt = undefined;
|
|
5369
|
+
submission.phase = "active";
|
|
5370
|
+
armPromptDeadline(key, correlation);
|
|
5371
|
+
return;
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5227
5374
|
submission.outcome = winner;
|
|
5228
5375
|
submission.phase = "terminalizing";
|
|
5229
5376
|
if (options.fence) {
|
|
@@ -5292,14 +5439,41 @@ export function createNotificationsExtension(
|
|
|
5292
5439
|
}
|
|
5293
5440
|
if (capture) capture.proof = proof;
|
|
5294
5441
|
}
|
|
5442
|
+
// Second deadline-attempt fence across the awaited fencing transition:
|
|
5443
|
+
// progress recorded while fencing was in flight supersedes exactly
|
|
5444
|
+
// like progress during the claim. Non-deadline attempts skip this —
|
|
5445
|
+
// their attempt identity was never registered.
|
|
5446
|
+
if (deadlineAttempt) {
|
|
5447
|
+
const key = promptSubmissionKey(correlation);
|
|
5448
|
+
const status = deadlineAttemptStatus(key, submission, deadlineAttempt);
|
|
5449
|
+
if (status === "stale") return;
|
|
5450
|
+
if (status === "superseded") {
|
|
5451
|
+
submission.deadlineAttempt = undefined;
|
|
5452
|
+
submission.phase = "active";
|
|
5453
|
+
armPromptDeadline(key, correlation);
|
|
5454
|
+
return;
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5295
5457
|
try {
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5458
|
+
if (deadlineAttempt) {
|
|
5459
|
+
await kindReconciliation.finalizeOutcome(
|
|
5460
|
+
submission.reconciliationKind,
|
|
5461
|
+
correlation,
|
|
5462
|
+
winner,
|
|
5463
|
+
() =>
|
|
5464
|
+
deadlineAttemptStatus(promptSubmissionKey(correlation), submission, deadlineAttempt) === "current",
|
|
5465
|
+
extra?.error,
|
|
5466
|
+
extra?.finalText,
|
|
5467
|
+
);
|
|
5468
|
+
} else {
|
|
5469
|
+
await kindReconciliation.finalizeOutcome(
|
|
5470
|
+
submission.reconciliationKind,
|
|
5471
|
+
correlation,
|
|
5472
|
+
winner,
|
|
5473
|
+
extra?.error,
|
|
5474
|
+
extra?.finalText,
|
|
5475
|
+
);
|
|
5476
|
+
}
|
|
5303
5477
|
} catch (error) {
|
|
5304
5478
|
// The durable pending claim survives; publishing an unpersisted terminal
|
|
5305
5479
|
// would contradict it, so fail the endpoint closed instead.
|
|
@@ -5307,6 +5481,18 @@ export function createNotificationsExtension(
|
|
|
5307
5481
|
failPromptClosed(correlation, submission, "terminal_uncertain", "Prompt reconciliation is unavailable.");
|
|
5308
5482
|
return;
|
|
5309
5483
|
}
|
|
5484
|
+
if (deadlineAttempt) {
|
|
5485
|
+
const key = promptSubmissionKey(correlation);
|
|
5486
|
+
const status = deadlineAttemptStatus(key, submission, deadlineAttempt);
|
|
5487
|
+
if (status === "stale") return;
|
|
5488
|
+
if (status === "superseded") {
|
|
5489
|
+
submission.deadlineAttempt = undefined;
|
|
5490
|
+
submission.phase = "active";
|
|
5491
|
+
armPromptDeadline(key, correlation);
|
|
5492
|
+
return;
|
|
5493
|
+
}
|
|
5494
|
+
submission.deadlineAttempt = undefined;
|
|
5495
|
+
}
|
|
5310
5496
|
if (submission.deadlineTimer) clearTimeout(submission.deadlineTimer);
|
|
5311
5497
|
if (!recordPromptTerminal(correlation)) return;
|
|
5312
5498
|
if (!runtime) {
|
|
@@ -5343,7 +5529,10 @@ export function createNotificationsExtension(
|
|
|
5343
5529
|
type: "agent_failed",
|
|
5344
5530
|
sessionId: runtime.id,
|
|
5345
5531
|
...correlation,
|
|
5346
|
-
error:
|
|
5532
|
+
error:
|
|
5533
|
+
extra?.error !== undefined
|
|
5534
|
+
? { code: extra.error.code, message: winner.message }
|
|
5535
|
+
: { code: winner.code, message: winner.message },
|
|
5347
5536
|
outcome: winner,
|
|
5348
5537
|
});
|
|
5349
5538
|
} else {
|
|
@@ -5401,12 +5590,12 @@ export function createNotificationsExtension(
|
|
|
5401
5590
|
error: formatPromptFailureForLocalLog(error),
|
|
5402
5591
|
});
|
|
5403
5592
|
const sanitized = sanitizePromptFailure(error);
|
|
5404
|
-
const outcome: SdkPromptTerminalOutcome = {
|
|
5405
|
-
kind: "failed",
|
|
5593
|
+
const outcome: SdkPromptTerminalOutcome = failedPromptOutcome({
|
|
5406
5594
|
code: "prompt_failed",
|
|
5407
|
-
message: sanitized.message,
|
|
5408
5595
|
provenance: "agent_failed",
|
|
5409
|
-
|
|
5596
|
+
providerCode: sanitized.code,
|
|
5597
|
+
evidence: {},
|
|
5598
|
+
});
|
|
5410
5599
|
// This rejection bypasses `agent_end`, so record its local-only reason at
|
|
5411
5600
|
// the accepted submission failure boundary before terminalization begins.
|
|
5412
5601
|
logger.error("sdk_prompt_terminal_failed", {
|
|
@@ -5469,6 +5658,7 @@ export function createNotificationsExtension(
|
|
|
5469
5658
|
selector => kindReconciliation.lookupResult(selector.kind, selector),
|
|
5470
5659
|
selector => kindReconciliation.lookupSteer(selector),
|
|
5471
5660
|
() => host,
|
|
5661
|
+
options.primaryControlSurface ?? "sdk",
|
|
5472
5662
|
),
|
|
5473
5663
|
id,
|
|
5474
5664
|
revisions,
|
|
@@ -7813,6 +8003,7 @@ export function createNotificationsExtension(
|
|
|
7813
8003
|
processIncarnation: hostProcessIncarnation,
|
|
7814
8004
|
});
|
|
7815
8005
|
throwIfLifecycleStopped();
|
|
8006
|
+
let registration: SessionIndexEvent | undefined;
|
|
7816
8007
|
await host.registerWithBroker({
|
|
7817
8008
|
// The endpoint is written before registration. Its exact mtime
|
|
7818
8009
|
// binds this index generation to that discovery record.
|
|
@@ -7826,7 +8017,7 @@ export function createNotificationsExtension(
|
|
|
7826
8017
|
processIncarnation: hostProcessIncarnation,
|
|
7827
8018
|
direct,
|
|
7828
8019
|
});
|
|
7829
|
-
await index.append({
|
|
8020
|
+
registration = await index.append({
|
|
7830
8021
|
type: "host_registered",
|
|
7831
8022
|
...input,
|
|
7832
8023
|
locator,
|
|
@@ -7843,13 +8034,16 @@ export function createNotificationsExtension(
|
|
|
7843
8034
|
});
|
|
7844
8035
|
},
|
|
7845
8036
|
unregister: async input => {
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
8037
|
+
const expected = registration;
|
|
8038
|
+
if (
|
|
8039
|
+
!expected ||
|
|
8040
|
+
expected.sessionId !== input.sessionId ||
|
|
8041
|
+
expected.endpointGeneration !== input.endpointGeneration ||
|
|
8042
|
+
path.resolve(expected.locator.stateRoot) !== path.resolve(input.stateRoot)
|
|
8043
|
+
)
|
|
8044
|
+
return;
|
|
8045
|
+
await index.unregisterIfCurrent(expected);
|
|
8046
|
+
if (registration === expected) registration = undefined;
|
|
7853
8047
|
},
|
|
7854
8048
|
});
|
|
7855
8049
|
throwIfLifecycleStopped();
|
|
@@ -8768,8 +8962,15 @@ export function createNotificationsExtension(
|
|
|
8768
8962
|
if (correlation) {
|
|
8769
8963
|
const assistants = (Array.isArray(event.messages) ? [...event.messages].reverse() : []).filter(
|
|
8770
8964
|
message => message && typeof message === "object" && (message as { role?: unknown }).role === "assistant",
|
|
8771
|
-
) as Array<{ stopReason?: unknown; errorKind?: unknown }>;
|
|
8965
|
+
) as Array<{ stopReason?: unknown; errorKind?: unknown; errorCode?: unknown }>;
|
|
8772
8966
|
const finalAssistant = assistants[0];
|
|
8967
|
+
const terminalAssistant = assistants.find(
|
|
8968
|
+
message =>
|
|
8969
|
+
(message as { stopReason?: unknown }).stopReason === "error" ||
|
|
8970
|
+
(message as { stopReason?: unknown }).stopReason === "aborted",
|
|
8971
|
+
) as
|
|
8972
|
+
| { stopReason?: "error" | "aborted"; errorMessage?: unknown; errorKind?: unknown; errorCode?: unknown }
|
|
8973
|
+
| undefined;
|
|
8773
8974
|
const pendingOutcome = rt.peekPromptPendingOutcome(correlation);
|
|
8774
8975
|
let outcome: SdkPromptTerminalOutcome;
|
|
8775
8976
|
if (pendingOutcome) outcome = pendingOutcome;
|
|
@@ -8786,24 +8987,24 @@ export function createNotificationsExtension(
|
|
|
8786
8987
|
finalAssistant?.stopReason !== "aborted"
|
|
8787
8988
|
)
|
|
8788
8989
|
outcome = { kind: "stopped", reason: "end_turn", provenance: "agent" };
|
|
8789
|
-
else
|
|
8790
|
-
|
|
8791
|
-
|
|
8990
|
+
else {
|
|
8991
|
+
// The provider/agent's own bounded classifier travels on the terminal
|
|
8992
|
+
// assistant message; the phase is finalized against the durable record
|
|
8993
|
+
// (startedAt) when the outcome is claimed.
|
|
8994
|
+
const providerCode = assistantFailureCode(terminalAssistant);
|
|
8995
|
+
outcome = failedPromptOutcome({
|
|
8792
8996
|
code: "prompt_failed",
|
|
8793
|
-
message: "Prompt submission failed.",
|
|
8794
8997
|
provenance: "agent_failed",
|
|
8795
|
-
|
|
8998
|
+
...(providerCode !== undefined ? { providerCode } : {}),
|
|
8999
|
+
evidence: {},
|
|
9000
|
+
});
|
|
9001
|
+
}
|
|
8796
9002
|
const successAssistant = assistants.find(
|
|
8797
9003
|
message => (message as { stopReason?: unknown }).stopReason === "stop",
|
|
8798
9004
|
);
|
|
8799
9005
|
const finalText = successAssistant ? acpFinalTextFromMessage(successAssistant).text : "";
|
|
8800
9006
|
// The normalized outcome is the ACP contract; existing SDK clients keep the
|
|
8801
9007
|
// legacy failure discriminator on the wire and in the reconciliation record.
|
|
8802
|
-
const terminalAssistant = assistants.find(
|
|
8803
|
-
message =>
|
|
8804
|
-
(message as { stopReason?: unknown }).stopReason === "error" ||
|
|
8805
|
-
(message as { stopReason?: unknown }).stopReason === "aborted",
|
|
8806
|
-
) as { stopReason?: "error" | "aborted"; errorMessage?: unknown; errorKind?: unknown } | undefined;
|
|
8807
9008
|
const legacyCode =
|
|
8808
9009
|
event.stopReason === "cancelled"
|
|
8809
9010
|
? "cancelled"
|
|
@@ -8835,7 +9036,7 @@ export function createNotificationsExtension(
|
|
|
8835
9036
|
? {
|
|
8836
9037
|
// Only the legacy discriminator is preserved; provider text is never
|
|
8837
9038
|
// retained, matching `sanitizePromptFailure`.
|
|
8838
|
-
error: { code: legacyCode, message:
|
|
9039
|
+
error: { code: legacyCode, message: outcome.message },
|
|
8839
9040
|
}
|
|
8840
9041
|
: {}),
|
|
8841
9042
|
});
|