@gajae-code/coding-agent 0.18.12 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +467 -0
- package/dist/types/capability/rule.d.ts +7 -2
- package/dist/types/cli/append-system-prompt.d.ts +6 -0
- package/dist/types/cli/args.d.ts +7 -2
- package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
- package/dist/types/cli/customize-doctor.d.ts +4 -3
- package/dist/types/cli/public-command-errors.d.ts +1 -0
- package/dist/types/cli/root-flags.d.ts +0 -12
- package/dist/types/cli/update-cli.d.ts +7 -2
- package/dist/types/cli-main.d.ts +0 -6
- package/dist/types/commands/launch.d.ts +0 -6
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +8 -0
- package/dist/types/commit/map-reduce/index.d.ts +4 -4
- package/dist/types/config/autorouting-tier-map.d.ts +23 -1
- package/dist/types/config/config-hot-reload.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +44 -2
- package/dist/types/config/model-profile-activation.d.ts +19 -5
- package/dist/types/config/model-registry.d.ts +16 -3
- package/dist/types/config/model-resolver.d.ts +5 -4
- package/dist/types/config/settings-schema.d.ts +11 -1
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/customization/import.d.ts +2 -0
- package/dist/types/customization/types.d.ts +1 -1
- package/dist/types/dap/session.d.ts +11 -2
- package/dist/types/discovery/helpers.d.ts +7 -2
- package/dist/types/edit/index.d.ts +5 -0
- package/dist/types/edit/modes/patch.d.ts +9 -0
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/export/ttsr.d.ts +19 -0
- package/dist/types/extensibility/extensions/types.d.ts +5 -1
- package/dist/types/extensibility/slash-commands.d.ts +1 -0
- package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/content.d.ts +5 -6
- package/dist/types/internal-urls/types.d.ts +2 -0
- package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
- package/dist/types/main.d.ts +23 -18
- package/dist/types/migrate/action-planner.d.ts +10 -1
- package/dist/types/migrate/adapters/codex.d.ts +1 -1
- package/dist/types/migrate/adapters/index.d.ts +35 -3
- package/dist/types/migrate/hook-module.d.ts +23 -0
- package/dist/types/migrate/report.d.ts +2 -1
- package/dist/types/migrate/types.d.ts +69 -2
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +43 -0
- package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
- package/dist/types/modes/utils/host-status.d.ts +15 -11
- package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
- package/dist/types/sdk/broker/broker-exit.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +22 -1
- package/dist/types/sdk/broker/ensure.d.ts +5 -2
- package/dist/types/sdk/broker/hop.d.ts +9 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
- package/dist/types/sdk/broker/session-index.d.ts +2 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/index.d.ts +21 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
- package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
- package/dist/types/sdk/host/control/operations.d.ts +5 -1
- package/dist/types/sdk/host/events.d.ts +4 -0
- package/dist/types/sdk/host/host.d.ts +2 -1
- package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
- package/dist/types/sdk/host/session-runtime.d.ts +8 -8
- package/dist/types/sdk/host/surface-policy.d.ts +2 -1
- package/dist/types/sdk/lifecycle/service.d.ts +12 -0
- package/dist/types/sdk/prompt-status.d.ts +11 -4
- package/dist/types/session/agent-session.d.ts +50 -8
- package/dist/types/session/session-manager.d.ts +16 -0
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +13 -1
- package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
- package/dist/types/ssh/ssh-executor.d.ts +8 -1
- package/dist/types/system-prompt.d.ts +3 -2
- package/dist/types/task/role-body.d.ts +11 -0
- package/dist/types/tools/awaiting-input.d.ts +28 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -0
- package/dist/types/tools/bash-skill-urls.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +7 -0
- package/dist/types/tools/descriptors.d.ts +13 -2
- package/dist/types/tools/fetch.d.ts +6 -0
- package/dist/types/tools/irc.d.ts +5 -3
- package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/utils/file-mentions.d.ts +5 -0
- package/dist/types/utils/image-limits.d.ts +7 -0
- package/dist/types/utils/image-loading.d.ts +0 -1
- package/dist/types/utils/open.d.ts +0 -1
- package/dist/types/utils/pasted-image-loading.d.ts +1 -5
- package/dist/types/utils/prompt-suggestion.d.ts +2 -2
- package/dist/types/utils/shell-snapshot.d.ts +2 -0
- package/dist/types/utils/title-generator.d.ts +13 -3
- package/dist/types/web/search/providers/codex.d.ts +6 -7
- package/package.json +9 -8
- package/scripts/acp-conformance-agent.ts +12 -2
- package/scripts/generate-sdk-operation-inventory.ts +16 -0
- package/src/capability/fs.ts +31 -3
- package/src/capability/rule.ts +11 -2
- package/src/cli/append-system-prompt.ts +12 -0
- package/src/cli/args.ts +11 -7
- package/src/cli/customize-doctor-precedence.ts +31 -0
- package/src/cli/customize-doctor.ts +49 -39
- package/src/cli/fast-help.ts +0 -2
- package/src/cli/migrate-cli.ts +14 -3
- package/src/cli/public-command-errors.ts +2 -0
- package/src/cli/root-flags.ts +0 -2
- package/src/cli/update-cli.ts +247 -6
- package/src/commands/harness.ts +25 -15
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +81 -11
- package/src/commit/agentic/agent.ts +6 -6
- package/src/commit/analysis/conventional.ts +14 -5
- package/src/commit/map-reduce/index.ts +7 -7
- package/src/commit/pipeline.ts +12 -12
- package/src/config/autorouting-tier-map.ts +20 -1
- package/src/config/config-file.ts +106 -3
- package/src/config/config-hot-reload.ts +8 -0
- package/src/config/file-lock.ts +1431 -304
- package/src/config/keybindings.ts +154 -7
- package/src/config/model-profile-activation.ts +177 -39
- package/src/config/model-registry.ts +380 -55
- package/src/config/model-resolver.ts +49 -21
- package/src/config/settings-schema.ts +13 -1
- package/src/config/settings.ts +2 -0
- package/src/coordinator-mcp/server.ts +37 -2
- package/src/crash/sanitize.ts +3 -1
- package/src/customization/import.ts +276 -7
- package/src/customization/inventory.ts +24 -8
- package/src/customization/types.ts +1 -0
- package/src/dap/client.ts +3 -2
- package/src/dap/session.ts +161 -36
- package/src/debug/crash-diagnostics.ts +87 -5
- package/src/debug/report-bundle.ts +71 -2
- package/src/discovery/builtin.ts +4 -3
- package/src/discovery/helpers.ts +24 -14
- package/src/edit/index.ts +191 -5
- package/src/edit/modes/patch.ts +27 -0
- package/src/eval/py/runtime.ts +44 -4
- package/src/exec/non-interactive-env.ts +0 -1
- package/src/export/html/index.ts +60 -20
- package/src/export/ttsr.ts +176 -1
- package/src/extensibility/extensions/loader.ts +2 -0
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
- package/src/extensibility/extensions/types.ts +5 -1
- package/src/extensibility/hooks/loader.ts +10 -2
- package/src/extensibility/plugins/marketplace/manager.ts +36 -10
- package/src/extensibility/slash-commands.ts +5 -0
- package/src/gjc-runtime/gc-runtime.ts +4 -1
- package/src/gjc-runtime/launch-tmux.ts +23 -13
- package/src/gjc-runtime/ralplan-current-final.ts +294 -0
- package/src/gjc-runtime/ralplan-runtime.ts +95 -1
- package/src/gjc-runtime/state-writer.ts +109 -5
- package/src/gjc-runtime/tmux-sessions.ts +93 -13
- package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
- package/src/gjc-runtime/ultragoal-guard.ts +9 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
- package/src/harness-control-plane/finalize.ts +11 -0
- package/src/harness-control-plane/receipt-spool.ts +105 -28
- package/src/harness-control-plane/storage.ts +124 -6
- package/src/hindsight/content.ts +116 -16
- package/src/hindsight/mental-models.ts +22 -10
- package/src/hindsight/state.ts +7 -4
- package/src/hooks/native-skill-hook.ts +3 -1
- package/src/internal-urls/artifact-protocol.ts +3 -1
- package/src/internal-urls/docs-index.generated.ts +14 -14
- package/src/internal-urls/local-protocol.ts +28 -3
- package/src/internal-urls/types.ts +2 -0
- package/src/lsp/client.ts +2 -1
- package/src/lsp/clients/biome-client.ts +2 -0
- package/src/lsp/clients/swiftlint-client.ts +2 -0
- package/src/main.ts +330 -92
- package/src/memories/index.ts +25 -2
- package/src/migrate/action-planner.ts +517 -2
- package/src/migrate/adapters/claude-code.ts +141 -3
- package/src/migrate/adapters/codex.ts +57 -5
- package/src/migrate/adapters/index.ts +240 -5
- package/src/migrate/adapters/opencode.ts +4 -0
- package/src/migrate/executor.ts +141 -3
- package/src/migrate/hook-module.ts +193 -0
- package/src/migrate/report.ts +45 -1
- package/src/migrate/types.ts +73 -3
- package/src/modes/acp/acp-agent.ts +10 -1
- package/src/modes/components/agent-dashboard.ts +20 -4
- package/src/modes/components/customization/customization-dashboard.ts +7 -0
- package/src/modes/components/customization/import-wizard.ts +29 -3
- package/src/modes/components/model-selector.ts +157 -103
- package/src/modes/components/welcome.ts +3 -1
- package/src/modes/controllers/command-controller.ts +271 -16
- package/src/modes/controllers/event-controller.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +31 -1
- package/src/modes/controllers/goal-mode-controller.ts +79 -10
- package/src/modes/controllers/input-controller.ts +2 -0
- package/src/modes/controllers/plan-mode-controller.ts +49 -4
- package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
- package/src/modes/controllers/selector-controller.ts +14 -1
- package/src/modes/interactive-mode.ts +55 -4
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +5 -1
- package/src/modes/utils/host-status.ts +21 -10
- package/src/prompts/agent-fragments/browser-aside.md +2 -2
- package/src/prompts/system/irc-incoming.md +3 -1
- package/src/prompts/tools/irc.md +1 -1
- package/src/runtime-mcp/manager.ts +8 -3
- package/src/runtime-mcp/project-host-values.ts +12 -8
- package/src/runtime-mcp/tool-bridge.ts +68 -4
- package/src/runtime-mcp/transports/stdio.ts +2 -1
- package/src/sdk/broker/broker-exit.ts +2 -0
- package/src/sdk/broker/broker.ts +143 -4
- package/src/sdk/broker/ensure.ts +74 -6
- package/src/sdk/broker/hop.ts +13 -1
- package/src/sdk/broker/lifecycle-ledger.ts +3 -0
- package/src/sdk/broker/lifecycle.ts +102 -6
- package/src/sdk/broker/session-index.ts +29 -4
- package/src/sdk/broker/transport.ts +17 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +408 -14
- package/src/sdk/bus/session-control.ts +2 -0
- package/src/sdk/bus/slack-daemon.ts +105 -9
- package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -2
- package/src/sdk/bus/threaded-render.ts +20 -1
- package/src/sdk/cli/session-cli.ts +2 -0
- package/src/sdk/host/control/dispatch.ts +13 -1
- package/src/sdk/host/control/operations.ts +10 -1
- package/src/sdk/host/events.ts +67 -4
- package/src/sdk/host/host.ts +8 -2
- package/src/sdk/host/prompt-image-upload.ts +438 -0
- package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
- package/src/sdk/host/session-runtime.test.ts +1537 -24
- package/src/sdk/host/session-runtime.ts +332 -36
- package/src/sdk/host/surface-policy.ts +4 -0
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
- package/src/sdk/host/websocket-transport.ts +19 -7
- package/src/sdk/lifecycle/service.ts +14 -1
- package/src/sdk/prompt-status.ts +6 -4
- package/src/sdk/protocol/adapter-validation.ts +28 -1
- package/src/sdk/protocol/operation-inventory.generated.json +160 -0
- package/src/sdk/protocol/operation-registry.ts +33 -3
- package/src/sdk/session.ts +123 -36
- package/src/session/agent-session.ts +1614 -329
- package/src/session/history-storage.ts +182 -12
- package/src/session/internal/managed-session-scope.ts +47 -18
- package/src/session/internal/managed-session-storage.ts +71 -1
- package/src/session/session-manager.ts +90 -5
- package/src/session-import/redact.ts +53 -2
- package/src/skill-state/workflow-mutation-guard.ts +1498 -18
- package/src/slash-commands/builtin-registry.ts +6 -3
- package/src/slash-commands/helpers/mcp.ts +11 -3
- package/src/ssh/ssh-executor.ts +9 -2
- package/src/stt/recorder.ts +26 -9
- package/src/system-prompt.ts +61 -16
- package/src/task/executor.ts +12 -8
- package/src/task/role-body.ts +84 -0
- package/src/task/token-log-mode.test.ts +162 -0
- package/src/task/token-log.ts +91 -2
- package/src/tools/archive-reader.ts +650 -37
- package/src/tools/ask.ts +1 -0
- package/src/tools/ast-grep.ts +7 -2
- package/src/tools/auto-generated-guard.ts +12 -3
- package/src/tools/awaiting-input.ts +114 -0
- package/src/tools/bash-allowed-prefixes.ts +61 -1
- package/src/tools/bash-skill-urls.ts +58 -5
- package/src/tools/bash.ts +99 -26
- package/src/tools/browser/tab-worker.ts +39 -13
- package/src/tools/browser.ts +17 -7
- package/src/tools/cron.ts +10 -1
- package/src/tools/debug.ts +9 -2
- package/src/tools/descriptors.test.ts +4 -4
- package/src/tools/descriptors.ts +16 -4
- package/src/tools/eval.ts +15 -0
- package/src/tools/fetch.ts +90 -2
- package/src/tools/gh.ts +27 -12
- package/src/tools/image-gen.ts +20 -6
- package/src/tools/irc.ts +5 -3
- package/src/tools/monitor.ts +9 -1
- package/src/tools/output-meta.ts +51 -3
- package/src/tools/read.ts +9 -2
- package/src/tools/recipe/runner.ts +23 -12
- package/src/tools/render-utils.ts +2 -2
- package/src/tools/search.ts +3 -2
- package/src/tools/ssh.ts +274 -8
- package/src/tools/subagent.ts +10 -4
- package/src/tools/tmux-self-injection-guard.ts +3301 -122
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/ultragoal-ask-guard.ts +13 -1
- package/src/tools/write.ts +7 -0
- package/src/tui/tree-list.ts +15 -1
- package/src/utils/commit-message-generator.ts +3 -2
- package/src/utils/external-editor.ts +21 -7
- package/src/utils/file-mentions.ts +46 -6
- package/src/utils/git.ts +38 -7
- package/src/utils/image-limits.ts +8 -0
- package/src/utils/image-loading.ts +1 -1
- package/src/utils/open.ts +73 -4
- package/src/utils/pasted-image-loading.ts +9 -8
- package/src/utils/prompt-suggestion.ts +5 -4
- package/src/utils/shell-snapshot.ts +9 -1
- package/src/utils/title-generator.ts +65 -20
- package/src/web/search/index.ts +2 -1
- package/src/web/search/providers/codex.ts +29 -32
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setSessionOutboundRedact } from "../host/events";
|
|
1
2
|
import {
|
|
2
3
|
type GenericNotificationSessionSource,
|
|
3
4
|
getCurrentTelegramActivationMarker,
|
|
@@ -480,6 +481,7 @@ export class NotificationSessionController {
|
|
|
480
481
|
policy: Omit<NotificationRuntimePolicy, "mode">,
|
|
481
482
|
mode: NotificationRuntimePolicy["mode"],
|
|
482
483
|
): void {
|
|
484
|
+
setSessionOutboundRedact(binding.sessionId, policy.redact);
|
|
483
485
|
runtime?.refreshPolicy?.(binding, { ...policy, mode });
|
|
484
486
|
}
|
|
485
487
|
|
|
@@ -58,6 +58,7 @@ function slackPublicationClientMsgId(publicationId: string): string {
|
|
|
58
58
|
|
|
59
59
|
// Durable filesystem publication leases must outlast one event-loop and persistence turn.
|
|
60
60
|
const MIN_PUBLICATION_LEASE_MS = 100;
|
|
61
|
+
const ROOT_PUBLICATION_POLL_MS = 50;
|
|
61
62
|
const INBOUND_REACTION_DEADLINE_MS = 5_000;
|
|
62
63
|
const RETIREMENT_DRAIN_MS = 5_000;
|
|
63
64
|
const INBOUND_REACTION = "eyes";
|
|
@@ -800,6 +801,7 @@ export class SlackNotificationDaemon {
|
|
|
800
801
|
endpointGeneration?: number,
|
|
801
802
|
requestedClientMsgId?: string,
|
|
802
803
|
): Promise<SlackRootPublication> {
|
|
804
|
+
const lifecycleGeneration = this.#lifecycleGeneration;
|
|
803
805
|
const endpoint = await this.#resolveAttachment(sessionId);
|
|
804
806
|
if (!endpoint || (endpointGeneration !== undefined && endpoint.generation !== endpointGeneration))
|
|
805
807
|
throw new SlackEndpointBindingError("Slack root publication requires the current session endpoint.");
|
|
@@ -816,7 +818,14 @@ export class SlackNotificationDaemon {
|
|
|
816
818
|
)
|
|
817
819
|
return current;
|
|
818
820
|
if (current?.state === "posting_root") {
|
|
819
|
-
|
|
821
|
+
// A live lease of our own belongs to an in-flight post; an expired one is
|
|
822
|
+
// reclaimed under a new fence exactly like a crashed peer's, otherwise the
|
|
823
|
+
// root waiter would re-enter postRoot forever.
|
|
824
|
+
if (
|
|
825
|
+
current.rootPublicationOwner === this.#publicationOwnerId &&
|
|
826
|
+
!this.#leaseExpired(current.rootPublicationLeaseExpiresAt, now)
|
|
827
|
+
)
|
|
828
|
+
return current;
|
|
820
829
|
claimed = true;
|
|
821
830
|
return nextRecord(current, {
|
|
822
831
|
rootPublicationOwner: this.#publicationOwnerId,
|
|
@@ -859,7 +868,17 @@ export class SlackNotificationDaemon {
|
|
|
859
868
|
}
|
|
860
869
|
if (!pending?.clientMsgId) throw new Error("Unable to persist Slack root post intent");
|
|
861
870
|
if (!claimed)
|
|
862
|
-
return {
|
|
871
|
+
return {
|
|
872
|
+
conversation: await this.#waitForRoot(
|
|
873
|
+
pendingKey,
|
|
874
|
+
sessionId,
|
|
875
|
+
body,
|
|
876
|
+
generation,
|
|
877
|
+
lifecycleGeneration,
|
|
878
|
+
endpoint.authorityId,
|
|
879
|
+
),
|
|
880
|
+
created: false,
|
|
881
|
+
};
|
|
863
882
|
if (pending.endpointGeneration !== generation) throw new SlackEndpointBindingError();
|
|
864
883
|
const clientMsgId = pending.clientMsgId;
|
|
865
884
|
const fence = pending.rootPublicationFence;
|
|
@@ -907,7 +926,7 @@ export class SlackNotificationDaemon {
|
|
|
907
926
|
// dispatch; resume performs any required replacement after reconciliation.
|
|
908
927
|
const active = await this.store.transact(pendingKey, current => {
|
|
909
928
|
if (
|
|
910
|
-
|
|
929
|
+
current?.state !== "posting_root" ||
|
|
911
930
|
current.clientMsgId !== clientMsgId ||
|
|
912
931
|
current.rootPublicationOwner !== this.#publicationOwnerId ||
|
|
913
932
|
current.rootPublicationFence !== fence
|
|
@@ -926,7 +945,17 @@ export class SlackNotificationDaemon {
|
|
|
926
945
|
});
|
|
927
946
|
if (!active) throw new Error("Slack root mapping disappeared");
|
|
928
947
|
if (active.state !== "active")
|
|
929
|
-
return {
|
|
948
|
+
return {
|
|
949
|
+
conversation: await this.#waitForRoot(
|
|
950
|
+
pendingKey,
|
|
951
|
+
sessionId,
|
|
952
|
+
body,
|
|
953
|
+
generation,
|
|
954
|
+
lifecycleGeneration,
|
|
955
|
+
endpoint.authorityId,
|
|
956
|
+
),
|
|
957
|
+
created: false,
|
|
958
|
+
};
|
|
930
959
|
return { conversation: active, created: createdRootEffect };
|
|
931
960
|
}
|
|
932
961
|
|
|
@@ -1267,8 +1296,12 @@ export class SlackNotificationDaemon {
|
|
|
1267
1296
|
)
|
|
1268
1297
|
return record;
|
|
1269
1298
|
inboundDispatches = [...(record.inboundDispatches ?? [])];
|
|
1299
|
+
// Fence the publisher before an abort-ignoring provider can renew or reactivate this mapping.
|
|
1270
1300
|
return nextRecord(record, {
|
|
1271
1301
|
state: "closed_marker",
|
|
1302
|
+
rootPublicationOwner: undefined,
|
|
1303
|
+
rootPublicationLeaseExpiresAt: undefined,
|
|
1304
|
+
rootPublicationFence: (record.rootPublicationFence ?? 0) + 1,
|
|
1272
1305
|
pendingActionId: undefined,
|
|
1273
1306
|
cleanupEffectId: undefined,
|
|
1274
1307
|
inboundDispatches: [],
|
|
@@ -3105,7 +3138,7 @@ export class SlackNotificationDaemon {
|
|
|
3105
3138
|
let renewed = false;
|
|
3106
3139
|
await this.store.transact(key, current => {
|
|
3107
3140
|
if (
|
|
3108
|
-
|
|
3141
|
+
current?.state !== "posting_root" ||
|
|
3109
3142
|
current.clientMsgId !== clientMsgId ||
|
|
3110
3143
|
current.rootPublicationOwner !== this.#publicationOwnerId ||
|
|
3111
3144
|
current.rootPublicationFence !== fence
|
|
@@ -3269,18 +3302,82 @@ export class SlackNotificationDaemon {
|
|
|
3269
3302
|
sessionId: string,
|
|
3270
3303
|
body: string,
|
|
3271
3304
|
endpointGeneration: number,
|
|
3305
|
+
lifecycleGeneration: number,
|
|
3306
|
+
attachmentAuthorityId?: string,
|
|
3272
3307
|
): Promise<SlackConversation> {
|
|
3273
|
-
|
|
3274
|
-
|
|
3308
|
+
// Another owner may renew this lease while provider work is active, so wait for the durable transition.
|
|
3309
|
+
while (true) {
|
|
3310
|
+
if (lifecycleGeneration !== this.#lifecycleGeneration)
|
|
3311
|
+
throw new Error("Slack daemon stopped while waiting for root publication");
|
|
3312
|
+
await Bun.sleep(ROOT_PUBLICATION_POLL_MS);
|
|
3313
|
+
if (lifecycleGeneration !== this.#lifecycleGeneration)
|
|
3314
|
+
throw new Error("Slack daemon stopped while waiting for root publication");
|
|
3275
3315
|
const current = await this.store.read(key);
|
|
3316
|
+
if (lifecycleGeneration !== this.#lifecycleGeneration)
|
|
3317
|
+
throw new Error("Slack daemon stopped while waiting for root publication");
|
|
3276
3318
|
if (current?.state === "active") {
|
|
3277
3319
|
const currentGeneration = this.#requireEndpointGeneration(current);
|
|
3278
|
-
if (currentGeneration === endpointGeneration)
|
|
3320
|
+
if (currentGeneration === endpointGeneration) {
|
|
3321
|
+
const endpoint = await this.#resolveAttachment(sessionId);
|
|
3322
|
+
if (lifecycleGeneration !== this.#lifecycleGeneration)
|
|
3323
|
+
throw new Error("Slack daemon stopped while waiting for root publication");
|
|
3324
|
+
if (
|
|
3325
|
+
!endpoint?.isCurrent() ||
|
|
3326
|
+
endpoint.sessionId !== sessionId ||
|
|
3327
|
+
endpoint.generation !== endpointGeneration ||
|
|
3328
|
+
endpoint.authorityId !== attachmentAuthorityId ||
|
|
3329
|
+
current.attachmentAuthorityId !== attachmentAuthorityId
|
|
3330
|
+
)
|
|
3331
|
+
throw new SlackEndpointBindingError("Slack root publication was retired before completion.");
|
|
3332
|
+
return current;
|
|
3333
|
+
}
|
|
3279
3334
|
if (currentGeneration > endpointGeneration)
|
|
3280
3335
|
throw new SlackEndpointBindingError("Slack root belongs to a newer endpoint generation.");
|
|
3281
3336
|
return await this.resume(sessionId, body, endpointGeneration);
|
|
3282
3337
|
}
|
|
3338
|
+
if (current?.state === "closed_marker") {
|
|
3339
|
+
const currentGeneration = this.#requireEndpointGeneration(current);
|
|
3340
|
+
if (currentGeneration > endpointGeneration)
|
|
3341
|
+
throw new SlackEndpointBindingError("Slack root belongs to a newer endpoint generation.");
|
|
3342
|
+
const endpoint = await this.#resolveAttachment(sessionId);
|
|
3343
|
+
if (lifecycleGeneration !== this.#lifecycleGeneration)
|
|
3344
|
+
throw new Error("Slack daemon stopped while waiting for root publication");
|
|
3345
|
+
if (
|
|
3346
|
+
!endpoint?.isCurrent() ||
|
|
3347
|
+
endpoint.sessionId !== sessionId ||
|
|
3348
|
+
endpoint.generation !== endpointGeneration ||
|
|
3349
|
+
endpoint.authorityId !== attachmentAuthorityId
|
|
3350
|
+
)
|
|
3351
|
+
throw new SlackEndpointBindingError("Slack root publication was retired before completion.");
|
|
3352
|
+
if (currentGeneration === endpointGeneration) {
|
|
3353
|
+
if (!current.rootTs)
|
|
3354
|
+
throw new SlackEndpointBindingError("Slack root publication was retired before completion.");
|
|
3355
|
+
if (
|
|
3356
|
+
current.rootPublicationOwner !== undefined &&
|
|
3357
|
+
!this.#leaseExpired(current.rootPublicationLeaseExpiresAt, this.#now())
|
|
3358
|
+
)
|
|
3359
|
+
continue;
|
|
3360
|
+
return await this.postRoot(sessionId, body, endpointGeneration);
|
|
3361
|
+
}
|
|
3362
|
+
if (
|
|
3363
|
+
current.rootPublicationOwner !== undefined &&
|
|
3364
|
+
!this.#leaseExpired(current.rootPublicationLeaseExpiresAt, this.#now())
|
|
3365
|
+
)
|
|
3366
|
+
continue;
|
|
3367
|
+
return await this.resume(sessionId, body, endpointGeneration);
|
|
3368
|
+
}
|
|
3369
|
+
if (current?.state === "resumed_root") {
|
|
3370
|
+
const currentGeneration = this.#requireEndpointGeneration(current);
|
|
3371
|
+
if (currentGeneration > endpointGeneration)
|
|
3372
|
+
throw new SlackEndpointBindingError("Slack root belongs to a newer endpoint generation.");
|
|
3373
|
+
if (
|
|
3374
|
+
current.rootPublicationOwner === undefined ||
|
|
3375
|
+
this.#leaseExpired(current.rootPublicationLeaseExpiresAt, this.#now())
|
|
3376
|
+
)
|
|
3377
|
+
return await this.resume(sessionId, body, endpointGeneration);
|
|
3378
|
+
}
|
|
3283
3379
|
if (
|
|
3380
|
+
current === undefined ||
|
|
3284
3381
|
current?.state === "error" ||
|
|
3285
3382
|
(current?.state === "posting_root" &&
|
|
3286
3383
|
this.#leaseExpired(current.rootPublicationLeaseExpiresAt, this.#now())) ||
|
|
@@ -3291,7 +3388,6 @@ export class SlackNotificationDaemon {
|
|
|
3291
3388
|
return await this.postRoot(sessionId, body, endpointGeneration);
|
|
3292
3389
|
}
|
|
3293
3390
|
}
|
|
3294
|
-
throw new Error("Slack root post is still pending");
|
|
3295
3391
|
}
|
|
3296
3392
|
|
|
3297
3393
|
async #waitForAction(key: string, sessionId: string, body: string, actionId: string): Promise<SlackConversation> {
|
|
@@ -303,8 +303,14 @@ export const SDK_LIFECYCLE_ROUTER_PROTOCOL_VERSION = 1;
|
|
|
303
303
|
* before its terminal record is durable.
|
|
304
304
|
* Generation 203 replaces owners that still treat a project `.gjc` file as an
|
|
305
305
|
* explicit deadline-autosave opt-in for a primary checkout.
|
|
306
|
+
* Generation 205 replaces owners whose process descendant walk can adopt
|
|
307
|
+
* children of a recycled PID. Generation 206 verifies macOS descendant
|
|
308
|
+
* identities and parentage before retaining PTY termination authority, and
|
|
309
|
+
* reaps adopted Linux PTY descendants when GJC is a child reaper.
|
|
310
|
+
* Generation 209 installs connection-owned private SDK image staging with
|
|
311
|
+
* execution-owned reservations, replacing hosts without that lifecycle contract.
|
|
306
312
|
*/
|
|
307
|
-
export const DAEMON_GENERATION =
|
|
313
|
+
export const DAEMON_GENERATION = 209;
|
|
308
314
|
|
|
309
315
|
/**
|
|
310
316
|
* Serving-compatibility boundary for daemon lifecycle requests. Epoch 7
|
|
@@ -302,6 +302,8 @@ export const ASK_SELECTED_ACK_CAPABILITY = "ask_selected_ack_v1";
|
|
|
302
302
|
export const ASK_CONTROLS_CAPABILITY = "ask_controls_v1";
|
|
303
303
|
/** Capability for the closed tool phase set: started, completed, failed, and cancelled. */
|
|
304
304
|
export const TOOL_ACTIVITY_CAPABILITY = "tool_activity_v2";
|
|
305
|
+
/** Receive content-free notifications when a running command needs host-side authentication. */
|
|
306
|
+
export const AWAITING_INPUT_CAPABILITY = "awaiting_input_v1";
|
|
305
307
|
/** Receive-only compatibility capability for pre-v2 hosts. */
|
|
306
308
|
export const LEGACY_TOOL_ACTIVITY_CAPABILITY = "tool_activity_v1";
|
|
307
309
|
/** Public `sdk/bus/telegram-daemon` path for the canonical `sdk/host` capability token. */
|
|
@@ -5428,6 +5430,7 @@ export class TelegramNotificationDaemon {
|
|
|
5428
5430
|
ASK_CONTROLS_CAPABILITY,
|
|
5429
5431
|
ASK_SELECTED_ACK_CAPABILITY,
|
|
5430
5432
|
TOOL_ACTIVITY_CAPABILITY,
|
|
5433
|
+
AWAITING_INPUT_CAPABILITY,
|
|
5431
5434
|
LEGACY_TOOL_ACTIVITY_CAPABILITY,
|
|
5432
5435
|
POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY,
|
|
5433
5436
|
"ephemeral_turn_v1",
|
|
@@ -7255,6 +7258,7 @@ export class TelegramNotificationDaemon {
|
|
|
7255
7258
|
"config_update",
|
|
7256
7259
|
"control_command_result",
|
|
7257
7260
|
"tool_activity",
|
|
7261
|
+
"awaiting_input",
|
|
7258
7262
|
"reasoning_summary",
|
|
7259
7263
|
]);
|
|
7260
7264
|
|
|
@@ -10874,8 +10878,12 @@ export class TelegramNotificationDaemon {
|
|
|
10874
10878
|
this.failLegacyToolStart(toolActivity);
|
|
10875
10879
|
await this.#failPublicationPreSend(publicationId, "topic authority is inactive or malformed");
|
|
10876
10880
|
}
|
|
10881
|
+
const flatSend =
|
|
10882
|
+
threadedFrame.type === "awaiting_input"
|
|
10883
|
+
? { ...send, text: `${send.text} · ${sessionTag(logicalSessionId)}` }
|
|
10884
|
+
: send;
|
|
10877
10885
|
if (!send.identity && !existingTopic && !this.flatIdentitySent.has(logicalSessionId)) {
|
|
10878
|
-
await this.deliverFlatFallback(logicalSessionId,
|
|
10886
|
+
await this.deliverFlatFallback(logicalSessionId, flatSend, toolActivity, socketLease, publicationId);
|
|
10879
10887
|
return;
|
|
10880
10888
|
}
|
|
10881
10889
|
const topicId =
|
|
@@ -10896,7 +10904,7 @@ export class TelegramNotificationDaemon {
|
|
|
10896
10904
|
abandonStaleToolStart();
|
|
10897
10905
|
return;
|
|
10898
10906
|
}
|
|
10899
|
-
await this.deliverFlatFallback(logicalSessionId,
|
|
10907
|
+
await this.deliverFlatFallback(logicalSessionId, flatSend, toolActivity, socketLease, publicationId);
|
|
10900
10908
|
return;
|
|
10901
10909
|
}
|
|
10902
10910
|
if (send.identity) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Pure rendering of threaded-session frames into Telegram send specs.
|
|
3
3
|
*
|
|
4
4
|
* The daemon receives the additive `ServerMessage` frames (identity_header,
|
|
5
|
-
* context_update, turn_stream, image_attachment, config_update) over the session
|
|
5
|
+
* context_update, turn_stream, image_attachment, config_update, awaiting_input) over the session
|
|
6
6
|
* WS and must turn each into a Bot API call scoped to the session's forum topic
|
|
7
7
|
* (`message_thread_id`), throttled through the shared rate-limit pool. This
|
|
8
8
|
* module is the pure frame→send mapping (including the priority lane and live-
|
|
@@ -80,6 +80,7 @@ interface ThreadedFrame {
|
|
|
80
80
|
// tool_activity
|
|
81
81
|
toolCallId?: unknown;
|
|
82
82
|
toolName?: unknown;
|
|
83
|
+
kind?: unknown;
|
|
83
84
|
argsSummary?: unknown;
|
|
84
85
|
resultSummary?: unknown;
|
|
85
86
|
isError?: unknown;
|
|
@@ -261,6 +262,24 @@ export function renderThreadedFrame(frame: ThreadedFrame): ThreadedSend | undefi
|
|
|
261
262
|
terminal: phase !== "started",
|
|
262
263
|
};
|
|
263
264
|
}
|
|
265
|
+
case "awaiting_input": {
|
|
266
|
+
const toolCallId = str(frame.toolCallId);
|
|
267
|
+
if (!toolCallId) return undefined;
|
|
268
|
+
let text: string;
|
|
269
|
+
switch (frame.kind) {
|
|
270
|
+
case "browser_auth":
|
|
271
|
+
text =
|
|
272
|
+
"⏳ A running command is waiting for browser sign-in. Finish it on the host; the agent continues when the command does.";
|
|
273
|
+
break;
|
|
274
|
+
case "device_code":
|
|
275
|
+
text =
|
|
276
|
+
"⏳ A running command is waiting for a device-code sign-in. Finish it on the host; the agent continues when the command does.";
|
|
277
|
+
break;
|
|
278
|
+
default:
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
return { method: "sendMessage", lane: "ask", text, coalesceKey: `awaiting:${toolCallId}` };
|
|
282
|
+
}
|
|
264
283
|
case "reasoning_summary": {
|
|
265
284
|
const text = str(frame.text);
|
|
266
285
|
if (!text) return undefined;
|
|
@@ -279,6 +279,8 @@ export function lifecyclePublicFailure(outcome: Extract<SessionLifecycleResult,
|
|
|
279
279
|
let diagnostic: PublicCommandDiagnosticCode | undefined;
|
|
280
280
|
if (outcome.error.code === "idempotency_conflict") {
|
|
281
281
|
diagnostic = "lifecycle_idempotency_conflict";
|
|
282
|
+
} else if (outcome.error.code === "legacy_lifecycle_ambiguous") {
|
|
283
|
+
diagnostic = "lifecycle_legacy_history_ambiguous";
|
|
282
284
|
} else if (LIFECYCLE_INPUT_REFUSAL_CODES.has(outcome.error.code)) {
|
|
283
285
|
diagnostic = "lifecycle_input_refused";
|
|
284
286
|
}
|
|
@@ -256,7 +256,19 @@ function invoke(
|
|
|
256
256
|
): Promise<ControlValue> | ControlValue {
|
|
257
257
|
switch (operation) {
|
|
258
258
|
case "turn.prompt":
|
|
259
|
-
return surface.prompt(text(input), input.images, input.clientRef as string | undefined);
|
|
259
|
+
return surface.prompt(text(input), input.images, input.clientRef as string | undefined, input.stagedImages);
|
|
260
|
+
case "turn.image.begin":
|
|
261
|
+
if (!surface.imageBegin) invalidInput("Image uploads are not installed for this session.");
|
|
262
|
+
return surface.imageBegin(input);
|
|
263
|
+
case "turn.image.append":
|
|
264
|
+
if (!surface.imageAppend) invalidInput("Image uploads are not installed for this session.");
|
|
265
|
+
return surface.imageAppend(input);
|
|
266
|
+
case "turn.image.finish":
|
|
267
|
+
if (!surface.imageFinish) invalidInput("Image uploads are not installed for this session.");
|
|
268
|
+
return surface.imageFinish(input);
|
|
269
|
+
case "turn.image.discard":
|
|
270
|
+
if (!surface.imageDiscard) invalidInput("Image uploads are not installed for this session.");
|
|
271
|
+
return surface.imageDiscard(input);
|
|
260
272
|
case "turn.steer":
|
|
261
273
|
return surface.steer(
|
|
262
274
|
text(input),
|
|
@@ -21,7 +21,16 @@ export type ControlInput = Record<string, unknown>;
|
|
|
21
21
|
* AgentSession and its controllers without exposing those concrete types here.
|
|
22
22
|
*/
|
|
23
23
|
export interface ControlSurface {
|
|
24
|
-
prompt(
|
|
24
|
+
prompt(
|
|
25
|
+
text: string,
|
|
26
|
+
images?: ControlValue,
|
|
27
|
+
clientRef?: string,
|
|
28
|
+
stagedImages?: ControlValue,
|
|
29
|
+
): Promise<ControlValue> | ControlValue;
|
|
30
|
+
imageBegin?(input: ControlValue): Promise<ControlValue> | ControlValue;
|
|
31
|
+
imageAppend?(input: ControlValue): Promise<ControlValue> | ControlValue;
|
|
32
|
+
imageFinish?(input: ControlValue): Promise<ControlValue> | ControlValue;
|
|
33
|
+
imageDiscard?(input: ControlValue): Promise<ControlValue> | ControlValue;
|
|
25
34
|
steer(text: string, clientRef?: string, expectedSdkRunToken?: string): Promise<ControlValue> | ControlValue;
|
|
26
35
|
followUp(text: string): Promise<ControlValue> | ControlValue;
|
|
27
36
|
abort(): Promise<ControlValue> | ControlValue;
|
package/src/sdk/host/events.ts
CHANGED
|
@@ -26,10 +26,37 @@ export interface EventReplay {
|
|
|
26
26
|
gap?: EventReplayGap;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/** Kinds emit sites suppress once notification redaction is on. */
|
|
30
|
+
const REDACTED_REPLAY_KINDS: ReadonlySet<string> = new Set([
|
|
31
|
+
"turn_stream",
|
|
32
|
+
"context_update",
|
|
33
|
+
"image_attachment",
|
|
34
|
+
"file_attachment",
|
|
35
|
+
"reasoning_summary",
|
|
36
|
+
"tool_activity",
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const outboundRedactBySession = new Map<string, boolean>();
|
|
40
|
+
|
|
41
|
+
/** Notification policy refresh records the live redaction bit for one session ring. */
|
|
42
|
+
export function setSessionOutboundRedact(sessionId: string, enabled: boolean): void {
|
|
43
|
+
outboundRedactBySession.set(sessionId, enabled);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function frameSessionId(frame: SdkFrame): string | undefined {
|
|
47
|
+
if (typeof frame.sessionId === "string") return frame.sessionId;
|
|
48
|
+
const payload = frame.payload;
|
|
49
|
+
if (!payload || typeof payload !== "object") return undefined;
|
|
50
|
+
const sessionId = (payload as { sessionId?: unknown }).sessionId;
|
|
51
|
+
return typeof sessionId === "string" ? sessionId : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
export class SessionEventStream {
|
|
30
55
|
#generation = 0;
|
|
31
56
|
#seq = 0;
|
|
32
57
|
#frames: EventFrame[] = [];
|
|
58
|
+
#outboundRedact = false;
|
|
59
|
+
#sessionId: string | undefined;
|
|
33
60
|
readonly #ringSize: number;
|
|
34
61
|
readonly #resyncQueries: string[];
|
|
35
62
|
readonly #revisionProvider: (() => number | undefined) | undefined;
|
|
@@ -55,6 +82,12 @@ export class SessionEventStream {
|
|
|
55
82
|
return this.#seq;
|
|
56
83
|
}
|
|
57
84
|
|
|
85
|
+
/** Follow the session redaction bit. Replay then drops kinds emit sites already suppress. */
|
|
86
|
+
setOutboundRedact(enabled: boolean): void {
|
|
87
|
+
this.#outboundRedact = enabled;
|
|
88
|
+
if (this.#sessionId !== undefined) outboundRedactBySession.set(this.#sessionId, enabled);
|
|
89
|
+
}
|
|
90
|
+
|
|
58
91
|
restart(): number {
|
|
59
92
|
this.#generation += 1;
|
|
60
93
|
this.#seq = 0;
|
|
@@ -63,6 +96,8 @@ export class SessionEventStream {
|
|
|
63
96
|
}
|
|
64
97
|
|
|
65
98
|
emit(frame: SdkFrame): EventFrame {
|
|
99
|
+
this.#noteSession(frame);
|
|
100
|
+
this.#noteConfigRedact(frame);
|
|
66
101
|
const suppliedRevision = frame.revision;
|
|
67
102
|
const providedRevision = this.#revisionProvider?.();
|
|
68
103
|
const revision =
|
|
@@ -85,10 +120,9 @@ export class SessionEventStream {
|
|
|
85
120
|
|
|
86
121
|
/** Replays retained current-generation events and reports any required resynchronization. */
|
|
87
122
|
replay(lastSeq: number, generation = this.#generation): EventReplay {
|
|
88
|
-
const events = this.#frames.filter(frame => frame.seq > lastSeq);
|
|
89
123
|
if (generation !== this.#generation) {
|
|
90
124
|
return {
|
|
91
|
-
events:
|
|
125
|
+
events: this.#visible(this.#frames),
|
|
92
126
|
gap: {
|
|
93
127
|
kind: "generation_reset",
|
|
94
128
|
fromGeneration: generation,
|
|
@@ -101,7 +135,7 @@ export class SessionEventStream {
|
|
|
101
135
|
const replayFrom = lastSeq + 1;
|
|
102
136
|
if (replayFrom < oldest) {
|
|
103
137
|
return {
|
|
104
|
-
events: this.#frames.filter(frame => frame.seq >= oldest),
|
|
138
|
+
events: this.#visible(this.#frames.filter(frame => frame.seq >= oldest)),
|
|
105
139
|
gap: {
|
|
106
140
|
kind: "sequence_gap",
|
|
107
141
|
fromSeq: replayFrom,
|
|
@@ -110,6 +144,35 @@ export class SessionEventStream {
|
|
|
110
144
|
},
|
|
111
145
|
};
|
|
112
146
|
}
|
|
113
|
-
return { events };
|
|
147
|
+
return { events: this.#visible(this.#frames.filter(frame => frame.seq > lastSeq)) };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#noteSession(frame: SdkFrame): void {
|
|
151
|
+
if (this.#sessionId !== undefined) return;
|
|
152
|
+
this.#sessionId = frameSessionId(frame);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#noteConfigRedact(frame: SdkFrame): void {
|
|
156
|
+
if (frame.kind !== "config_update") return;
|
|
157
|
+
const payload = frame.payload;
|
|
158
|
+
if (!payload || typeof payload !== "object") return;
|
|
159
|
+
const redact = (payload as { redact?: unknown }).redact;
|
|
160
|
+
if (typeof redact !== "boolean") return;
|
|
161
|
+
this.setOutboundRedact(redact);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#replayRedact(): boolean {
|
|
165
|
+
if (this.#sessionId !== undefined) {
|
|
166
|
+
const noted = outboundRedactBySession.get(this.#sessionId);
|
|
167
|
+
if (noted !== undefined) return noted;
|
|
168
|
+
}
|
|
169
|
+
return this.#outboundRedact;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#visible(frames: readonly EventFrame[]): EventFrame[] {
|
|
173
|
+
const retained = this.#replayRedact()
|
|
174
|
+
? frames.filter(frame => !REDACTED_REPLAY_KINDS.has(String(frame.kind)))
|
|
175
|
+
: frames;
|
|
176
|
+
return [...retained];
|
|
114
177
|
}
|
|
115
178
|
}
|
package/src/sdk/host/host.ts
CHANGED
|
@@ -103,6 +103,7 @@ export interface SessionSdkHostOptions extends HostEndpointAdapters {
|
|
|
103
103
|
* must see the same capability-gated event kinds on both legs, or live and
|
|
104
104
|
* replay delivery diverge for the same subscriber. */
|
|
105
105
|
export const TOOL_ACTIVITY_CAPABILITY = "tool_activity_v2";
|
|
106
|
+
export const AWAITING_INPUT_CAPABILITY = "awaiting_input_v1";
|
|
106
107
|
/** Capability for non-replayable streamed turn content. */
|
|
107
108
|
export const TURN_STREAM_CAPABILITY = "turn_stream";
|
|
108
109
|
/** Capability used by notification adapters that observe a host without owning its work. */
|
|
@@ -113,12 +114,17 @@ export const SESSION_HOST_OBSERVER_CAPABILITY = "session_host_observer_v1";
|
|
|
113
114
|
* of every frame its positioned envelope already reached.
|
|
114
115
|
*/
|
|
115
116
|
export const POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY = "positioned_notification_effects_v1";
|
|
116
|
-
export const CAP_GATED_FRAME_KINDS:
|
|
117
|
+
export const CAP_GATED_FRAME_KINDS: ReadonlyMap<string, string> = new Map([
|
|
118
|
+
["tool_activity", TOOL_ACTIVITY_CAPABILITY],
|
|
119
|
+
["reasoning_summary", TOOL_ACTIVITY_CAPABILITY],
|
|
120
|
+
["awaiting_input", AWAITING_INPUT_CAPABILITY],
|
|
121
|
+
]);
|
|
117
122
|
const EMPTY_CAPABILITIES: ReadonlySet<string> = new Set();
|
|
118
123
|
|
|
119
124
|
/** Keep live delivery and replay on one capability gate. */
|
|
120
125
|
export function canDeliverSdkEvent(kind: string, capabilities: ReadonlySet<string> | undefined): boolean {
|
|
121
|
-
|
|
126
|
+
const requiredCapability = CAP_GATED_FRAME_KINDS.get(kind);
|
|
127
|
+
return requiredCapability === undefined || capabilities?.has(requiredCapability) === true;
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
/** Safe, identifier-free explanations for every refused activation status. */
|