@sayknow-cli/coding-agent 0.3.7 → 0.3.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/dist/types/append-only-mode.d.ts +31 -0
- package/dist/types/capability/rule.d.ts +8 -0
- package/dist/types/cli/completion-cli.d.ts +41 -0
- package/dist/types/cli/config-cli.d.ts +1 -0
- package/dist/types/cli/fixture-report.d.ts +20 -0
- package/dist/types/cli/fixture-report.test.d.ts +1 -0
- package/dist/types/cli/nofile-limit.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +7 -0
- package/dist/types/cli/update-cli.d.ts +22 -0
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/commands/completion.d.ts +29 -0
- package/dist/types/commands/config.d.ts +3 -0
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +7 -6
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +6 -0
- package/dist/types/config/model-profiles.d.ts +1 -0
- package/dist/types/config/settings-schema.d.ts +105 -1
- package/dist/types/config/settings.d.ts +8 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/export/ttsr.d.ts +14 -3
- package/dist/types/extensibility/extensions/runner.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/hooks/native-skill-hook.d.ts +12 -0
- package/dist/types/main.d.ts +4 -1
- package/dist/types/modes/components/assistant-message.d.ts +5 -1
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +9 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +5 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/print-mode.d.ts +13 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/notifications/config.d.ts +14 -1
- package/dist/types/notifications/daemon-paths.d.ts +1 -0
- package/dist/types/notifications/index.d.ts +6 -3
- package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
- package/dist/types/notifications/telegram-daemon.d.ts +23 -3
- package/dist/types/notifications/telegram-reference.d.ts +0 -5
- package/dist/types/notifications/threaded-render.d.ts +6 -0
- package/dist/types/runtime-api-key.d.ts +7 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +61 -6
- package/dist/types/session/agent-storage.d.ts +1 -0
- package/dist/types/session/file-mention-pruning.d.ts +8 -0
- package/dist/types/session/messages.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +17 -1
- package/dist/types/skc-runtime/deep-interview-ambiguity.d.ts +39 -0
- package/dist/types/skc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/skc-runtime/deep-interview-state.d.ts +17 -2
- package/dist/types/skc-runtime/session-state-sidecar.d.ts +7 -0
- package/dist/types/skc-runtime/state-writer.d.ts +3 -0
- package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
- package/dist/types/skc-runtime/ultragoal-runtime.d.ts +120 -13
- package/dist/types/skill-state/active-state.d.ts +18 -1
- package/dist/types/system-prompt.d.ts +18 -2
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/fork-context-budget.d.ts +7 -0
- package/dist/types/task/token-log.d.ts +30 -0
- package/dist/types/task/token-log.test.d.ts +1 -0
- package/dist/types/tools/bisect.d.ts +81 -0
- package/dist/types/tools/computer.d.ts +2 -2
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/search.d.ts +2 -2
- package/dist/types/tools/ultragoal-ask-guard.d.ts +9 -2
- package/dist/types/utils/file-mentions.d.ts +14 -0
- package/dist/types/utils/git.d.ts +32 -0
- package/dist/types/web/scrapers/youtube.d.ts +8 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
- package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
- package/package.json +8 -8
- package/src/append-only-mode.ts +58 -0
- package/src/autoresearch/prompt.md +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/capability/rule.ts +9 -0
- package/src/cli/completion-cli.ts +234 -0
- package/src/cli/config-cli.ts +61 -9
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/fixture-report.test.ts +230 -0
- package/src/cli/fixture-report.ts +171 -0
- package/src/cli/nofile-limit.ts +48 -0
- package/src/cli/notify-cli.ts +92 -8
- package/src/cli/telegram-cli.ts +1 -1
- package/src/cli/update-cli.ts +85 -9
- package/src/cli.ts +29 -1
- package/src/commands/completion.ts +84 -0
- package/src/commands/config.ts +2 -0
- package/src/commands/contribution-prep.ts +1 -1
- package/src/commands/deep-interview.ts +2 -1
- package/src/config/file-lock.ts +73 -34
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +65 -0
- package/src/config/model-profiles.ts +31 -2
- package/src/config/settings-schema.ts +68 -1
- package/src/config/settings.ts +22 -0
- package/src/defaults/skc/skills/team/SKILL.md +17 -14
- package/src/defaults/skc/skills/ultragoal/SKILL.md +59 -4
- package/src/defaults/skc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
- package/src/defaults/skc-defaults.ts +9 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/index.ts +1 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +60 -2
- package/src/export/ttsr.ts +96 -18
- package/src/extensibility/extensions/runner.ts +183 -219
- package/src/extensibility/extensions/types.ts +9 -0
- package/src/extensibility/skc-plugins/runtime-adapters.ts +156 -44
- package/src/goals/runtime.ts +10 -2
- package/src/hindsight/backend.ts +1 -3
- package/src/hooks/native-skill-hook.ts +124 -4
- package/src/internal-urls/docs-index.generated.ts +14 -5
- package/src/main.ts +95 -43
- package/src/memories/index.ts +12 -1
- package/src/modes/components/assistant-message.ts +241 -82
- package/src/modes/components/custom-editor.ts +1 -0
- package/src/modes/components/model-selector.ts +54 -11
- package/src/modes/components/queued-message-selector.ts +92 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/components/status-line.ts +167 -54
- package/src/modes/components/tool-execution.ts +44 -19
- package/src/modes/components/welcome.ts +181 -44
- package/src/modes/controllers/command-controller.ts +40 -4
- package/src/modes/controllers/event-controller.ts +66 -47
- package/src/modes/controllers/extension-ui-controller.ts +4 -10
- package/src/modes/controllers/input-controller.ts +180 -18
- package/src/modes/controllers/selector-controller.ts +127 -24
- package/src/modes/interactive-mode.ts +51 -16
- package/src/modes/print-mode.ts +43 -4
- package/src/modes/prompt-action-autocomplete.ts +21 -20
- package/src/modes/rpc/rpc-mode.ts +29 -3
- package/src/modes/rpc/rpc-types.ts +9 -0
- package/src/modes/shared/agent-wire/command-validation.ts +4 -0
- package/src/modes/shared/agent-wire/event-contract.ts +22 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
- package/src/modes/shared/agent-wire/scopes.ts +1 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +20 -7
- package/src/notifications/config.ts +25 -5
- package/src/notifications/daemon-paths.ts +2 -0
- package/src/notifications/index.ts +117 -14
- package/src/notifications/lifecycle-commands.ts +37 -7
- package/src/notifications/lifecycle-orchestrator.ts +19 -6
- package/src/notifications/telegram-daemon-control.ts +5 -3
- package/src/notifications/telegram-daemon.ts +302 -51
- package/src/notifications/telegram-reference.ts +0 -16
- package/src/notifications/threaded-render.ts +17 -1
- package/src/prompts/agents/architect.md +19 -10
- package/src/prompts/agents/critic.md +16 -18
- package/src/prompts/agents/executor.md +14 -11
- package/src/prompts/agents/planner.md +18 -13
- package/src/prompts/ci-green-request.md +3 -8
- package/src/prompts/goals/goal-continuation.md +0 -5
- package/src/prompts/goals/goal-mode-active.md +0 -5
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/plan-mode-subagent.md +3 -3
- package/src/prompts/system/project-prompt.md +0 -13
- package/src/prompts/system/subagent-system-prompt.md +3 -2
- package/src/prompts/system/system-prompt.md +29 -17
- package/src/prompts/system/volatile-project-context.md +10 -0
- package/src/prompts/system/web-search.md +4 -7
- package/src/prompts/tools/apply-patch.md +6 -0
- package/src/prompts/tools/ast-edit.md +1 -0
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/bisect.md +22 -0
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/computer.md +2 -2
- package/src/prompts/tools/cron.md +0 -2
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/github.md +6 -6
- package/src/prompts/tools/goal.md +1 -3
- package/src/prompts/tools/image-gen.md +12 -5
- package/src/prompts/tools/irc.md +5 -4
- package/src/prompts/tools/job.md +2 -2
- package/src/prompts/tools/lsp.md +1 -1
- package/src/prompts/tools/monitor.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/replace.md +2 -21
- package/src/prompts/tools/rewind.md +1 -1
- package/src/prompts/tools/search-tool-bm25.md +1 -11
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/skill.md +3 -2
- package/src/prompts/tools/ssh.md +2 -1
- package/src/prompts/tools/subagent.md +2 -2
- package/src/prompts/tools/task.md +4 -5
- package/src/prompts/tools/todo-write.md +1 -1
- package/src/prompts/tools/vim.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/prompts/tools/write.md +8 -2
- package/src/runtime-api-key.ts +16 -0
- package/src/sdk.ts +52 -28
- package/src/session/agent-session.ts +1011 -141
- package/src/session/agent-storage.ts +4 -0
- package/src/session/file-mention-pruning.ts +64 -0
- package/src/session/messages.ts +4 -0
- package/src/session/session-manager.ts +103 -4
- package/src/skc-runtime/deep-interview-ambiguity.ts +206 -0
- package/src/skc-runtime/deep-interview-recorder.ts +62 -8
- package/src/skc-runtime/deep-interview-state.ts +44 -2
- package/src/skc-runtime/session-state-sidecar.ts +263 -20
- package/src/skc-runtime/state-runtime.ts +12 -2
- package/src/skc-runtime/state-writer.ts +15 -0
- package/src/skc-runtime/ultragoal-guard.ts +55 -66
- package/src/skc-runtime/ultragoal-receipt-freshness.ts +315 -0
- package/src/skc-runtime/ultragoal-runtime.ts +1663 -159
- package/src/skc-runtime/workflow-manifest.generated.json +113 -2
- package/src/skc-runtime/workflow-manifest.ts +74 -1
- package/src/skill-state/active-state.ts +141 -5
- package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
- package/src/slash-commands/builtin-registry.ts +218 -71
- package/src/system-prompt.ts +57 -16
- package/src/task/executor.ts +132 -24
- package/src/task/fork-context-advisory.ts +2 -7
- package/src/task/fork-context-budget.ts +9 -0
- package/src/task/index.ts +13 -6
- package/src/task/output-manager.ts +20 -8
- package/src/task/receipt.ts +26 -7
- package/src/task/token-log.test.ts +188 -0
- package/src/task/token-log.ts +179 -0
- package/src/tools/bisect.ts +367 -0
- package/src/tools/computer.ts +246 -43
- package/src/tools/index.ts +3 -0
- package/src/tools/output-meta.ts +116 -4
- package/src/tools/search.ts +8 -2
- package/src/tools/skill.ts +15 -0
- package/src/tools/telegram-send.ts +6 -0
- package/src/tools/ultragoal-ask-guard.ts +39 -5
- package/src/utils/file-mentions.ts +39 -7
- package/src/utils/git.ts +73 -0
- package/src/web/scrapers/youtube.ts +24 -12
- package/src/workflow/workflow-intent-diff.ts +29 -6
- package/src/workflow/workflow-intent-report-consumer.ts +221 -0
- package/src/workflow/workflow-intent-report-schema.ts +129 -0
- package/src/workflow/workflow-intent-report.ts +135 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type AutocompleteItem,
|
|
3
|
+
type AutocompleteProvider,
|
|
4
|
+
CombinedAutocompleteProvider,
|
|
5
|
+
extractSlashCommandTokenPrefix,
|
|
6
|
+
getKeybindings,
|
|
7
|
+
getSlashCommandMatchRank,
|
|
8
|
+
type SlashCommand,
|
|
9
|
+
} from "@sayknow-cli/tui";
|
|
3
10
|
import type { KeybindingsManager } from "../config/keybindings";
|
|
4
11
|
import { formatKeyHints } from "../config/keybindings";
|
|
5
12
|
import { isSettingsInitialized, settings } from "../config/settings";
|
|
@@ -147,6 +154,10 @@ function sortSlashCommandSuggestions(
|
|
|
147
154
|
return { ...suggestions, items };
|
|
148
155
|
}
|
|
149
156
|
|
|
157
|
+
function isRootPathSuggestionResult(suggestions: { items: AutocompleteItem[]; prefix: string } | null): boolean {
|
|
158
|
+
return suggestions?.prefix.startsWith("/") === true && suggestions.items.some(item => item.value.startsWith("/"));
|
|
159
|
+
}
|
|
160
|
+
|
|
150
161
|
function withoutSkillCommandSuggestions(
|
|
151
162
|
suggestions: { items: AutocompleteItem[]; prefix: string } | null,
|
|
152
163
|
): { items: AutocompleteItem[]; prefix: string } | null {
|
|
@@ -168,18 +179,9 @@ function getPromptActionPrefix(textBeforeCursor: string): string | null {
|
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
function getSlashTokenPrefix(textBeforeCursor: string): string | null {
|
|
171
|
-
|
|
172
|
-
if (slashIndex === -1) return null;
|
|
173
|
-
const beforeSlash = textBeforeCursor.slice(0, slashIndex);
|
|
174
|
-
if (beforeSlash && !/\s$/.test(beforeSlash)) return null;
|
|
175
|
-
const token = textBeforeCursor.slice(slashIndex);
|
|
176
|
-
if (/[\s]/.test(token)) return null;
|
|
177
|
-
return token;
|
|
182
|
+
return extractSlashCommandTokenPrefix(textBeforeCursor);
|
|
178
183
|
}
|
|
179
184
|
|
|
180
|
-
function isLeadingSlashToken(textBeforeCursor: string, slashPrefix: string): boolean {
|
|
181
|
-
return textBeforeCursor.trimStart() === slashPrefix;
|
|
182
|
-
}
|
|
183
185
|
export class PromptActionAutocompleteProvider implements AutocompleteProvider {
|
|
184
186
|
#baseProvider: CombinedAutocompleteProvider;
|
|
185
187
|
#actions: PromptActionDefinition[];
|
|
@@ -226,14 +228,13 @@ export class PromptActionAutocompleteProvider implements AutocompleteProvider {
|
|
|
226
228
|
|
|
227
229
|
const slashPrefix = getSlashTokenPrefix(textBeforeCursor);
|
|
228
230
|
if (slashPrefix) {
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const skillCommandSuggestions =
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
: null;
|
|
231
|
+
const baseSuggestions = withoutSkillCommandSuggestions(
|
|
232
|
+
await this.#baseProvider.getSuggestions(lines, cursorLine, cursorCol),
|
|
233
|
+
);
|
|
234
|
+
if (isRootPathSuggestionResult(baseSuggestions)) return baseSuggestions;
|
|
235
|
+
const skillCommandSuggestions = this.#getSkillCommandSuggestions(textBeforeCursor, {
|
|
236
|
+
includeEmpty: false,
|
|
237
|
+
});
|
|
237
238
|
return sortSlashCommandSuggestions(
|
|
238
239
|
mergeAutocompleteSuggestions(baseSuggestions, skillCommandSuggestions),
|
|
239
240
|
this.#commands,
|
|
@@ -22,8 +22,13 @@ import type { AgentSession } from "../../session/agent-session";
|
|
|
22
22
|
import { workflowGatePath } from "../../skc-runtime/session-layout";
|
|
23
23
|
import { initializeExtensions } from "../runtime-init";
|
|
24
24
|
import { dispatchRpcCommand } from "../shared/agent-wire/command-dispatch";
|
|
25
|
-
import {
|
|
26
|
-
|
|
25
|
+
import {
|
|
26
|
+
AgentWireCompactEventEncoder,
|
|
27
|
+
AgentWireFrameSequencer,
|
|
28
|
+
toAgentWireCompactEventFrame,
|
|
29
|
+
toAgentWireEventFrame,
|
|
30
|
+
} from "../shared/agent-wire/event-envelope";
|
|
31
|
+
import { rpcError as error, rpcSuccess } from "../shared/agent-wire/responses";
|
|
27
32
|
import { registerRpcSession, unregisterRpcSession } from "../shared/agent-wire/session-registry";
|
|
28
33
|
import { defaultAuditPath, UnattendedAuditLog } from "../shared/agent-wire/unattended-audit";
|
|
29
34
|
import { modelSupportsTokenCostMetrics, UnattendedSessionControlPlane } from "../shared/agent-wire/unattended-session";
|
|
@@ -297,6 +302,7 @@ export async function runRpcMode(
|
|
|
297
302
|
output({ type: "ready" });
|
|
298
303
|
}
|
|
299
304
|
const emitRpcTitles = shouldEmitRpcTitles();
|
|
305
|
+
const rpcCapabilities = { compactMessageUpdate: false };
|
|
300
306
|
const decodeError = (err: unknown): string => (err instanceof Error ? err.message : String(err));
|
|
301
307
|
|
|
302
308
|
const pendingExtensionRequests = new Map<string, PendingExtensionRequest>();
|
|
@@ -636,8 +642,13 @@ export async function runRpcMode(
|
|
|
636
642
|
// Output all agent events as canonical agent-wire `event` frames (docs/rpc.md):
|
|
637
643
|
// { type:"event", protocol_version, session_id, seq, frame_id, payload:{ event_type, event } }.
|
|
638
644
|
const eventSequencer = new AgentWireFrameSequencer(session.sessionId);
|
|
645
|
+
const compactEventEncoder = new AgentWireCompactEventEncoder(eventSequencer);
|
|
639
646
|
session.subscribe(event => {
|
|
640
|
-
output(
|
|
647
|
+
output(
|
|
648
|
+
rpcCapabilities.compactMessageUpdate
|
|
649
|
+
? toAgentWireCompactEventFrame(event, compactEventEncoder)
|
|
650
|
+
: toAgentWireEventFrame(event, eventSequencer),
|
|
651
|
+
);
|
|
641
652
|
});
|
|
642
653
|
|
|
643
654
|
// Handle a single command through the shared agent-wire dispatcher so RPC
|
|
@@ -710,6 +721,21 @@ export async function runRpcMode(
|
|
|
710
721
|
hostUriBridge.handleResult(parsed);
|
|
711
722
|
return;
|
|
712
723
|
}
|
|
724
|
+
if ((parsed as RpcCommand).type === "set_capabilities") {
|
|
725
|
+
// RPC has no startup handshake; clients negotiate optional event-shape capabilities
|
|
726
|
+
// with this explicit command. Defaults remain legacy/full-frame until accepted here.
|
|
727
|
+
const command = parsed as Extract<RpcCommand, { type: "set_capabilities" }>;
|
|
728
|
+
const requested = Array.isArray(command.capabilities) ? command.capabilities : [];
|
|
729
|
+
const acceptedCapabilities = requested.filter(capability => capability === "compact_message_update");
|
|
730
|
+
rpcCapabilities.compactMessageUpdate = acceptedCapabilities.includes("compact_message_update");
|
|
731
|
+
output(
|
|
732
|
+
rpcSuccess(command.id, "set_capabilities", {
|
|
733
|
+
acceptedCapabilities,
|
|
734
|
+
unsupported: requested.filter(capability => capability !== "compact_message_update"),
|
|
735
|
+
}),
|
|
736
|
+
);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
713
739
|
// Ordered commands run through a serial chain to preserve causal order; the
|
|
714
740
|
// reader never blocks, so cancellation commands stay responsive even while a
|
|
715
741
|
// long command is in flight (issue 13).
|
|
@@ -13,6 +13,7 @@ import type { SessionStats } from "../../session/agent-session";
|
|
|
13
13
|
import type { TodoPhase } from "../../tools/todo-write";
|
|
14
14
|
|
|
15
15
|
export type RpcGetStateInclude = "tools" | "dumpTools" | "systemPrompt";
|
|
16
|
+
export type RpcCapability = "compact_message_update";
|
|
16
17
|
|
|
17
18
|
// ============================================================================
|
|
18
19
|
// RPC Commands (stdin)
|
|
@@ -33,6 +34,7 @@ export type RpcCommand =
|
|
|
33
34
|
| { id?: string; type: "set_host_tools"; tools: RpcHostToolDefinition[] }
|
|
34
35
|
| { id?: string; type: "set_host_uri_schemes"; schemes: RpcHostUriSchemeDefinition[] }
|
|
35
36
|
| { id?: string; type: "get_pending_workflow_gates" }
|
|
37
|
+
| { id?: string; type: "set_capabilities"; capabilities: RpcCapability[] }
|
|
36
38
|
|
|
37
39
|
// Model
|
|
38
40
|
| { id?: string; type: "set_model"; provider: string; modelId: string }
|
|
@@ -140,6 +142,13 @@ export type RpcResponse =
|
|
|
140
142
|
success: true;
|
|
141
143
|
data: { gates: RpcWorkflowGate[] };
|
|
142
144
|
}
|
|
145
|
+
| {
|
|
146
|
+
id?: string;
|
|
147
|
+
type: "response";
|
|
148
|
+
command: "set_capabilities";
|
|
149
|
+
success: true;
|
|
150
|
+
data: { acceptedCapabilities: RpcCapability[]; unsupported: string[] };
|
|
151
|
+
}
|
|
143
152
|
|
|
144
153
|
// Model
|
|
145
154
|
| {
|
|
@@ -130,6 +130,10 @@ export function isRpcCommand(value: unknown): value is RpcCommand {
|
|
|
130
130
|
return Array.isArray(value.tools) && value.tools.every(hostToolDefinition);
|
|
131
131
|
case "set_host_uri_schemes":
|
|
132
132
|
return Array.isArray(value.schemes) && value.schemes.every(hostUriScheme);
|
|
133
|
+
case "set_capabilities":
|
|
134
|
+
return (
|
|
135
|
+
Array.isArray(value.capabilities) && value.capabilities.every(capability => typeof capability === "string")
|
|
136
|
+
);
|
|
133
137
|
case "set_model":
|
|
134
138
|
return stringField(value, "provider") && stringField(value, "modelId");
|
|
135
139
|
case "set_thinking_level":
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* an `AgentSessionEvent` variant fails typecheck until it is registered, and so
|
|
14
14
|
* conformance tests can assert fixture coverage equals the registry exactly.
|
|
15
15
|
*/
|
|
16
|
+
|
|
17
|
+
import type { AssistantMessageEvent } from "@sayknow-cli/ai";
|
|
16
18
|
import type { AgentSessionEvent } from "../../../session/agent-session";
|
|
17
19
|
|
|
18
20
|
/** Wire protocol version. Bump on breaking envelope/semantic changes. */
|
|
@@ -68,6 +70,25 @@ export interface AgentWireEventPayload {
|
|
|
68
70
|
event_type: AgentWireEventType;
|
|
69
71
|
event: AgentSessionEvent;
|
|
70
72
|
}
|
|
73
|
+
export type AgentWireCompactAssistantMessageEvent = AssistantMessageEvent extends infer TEvent
|
|
74
|
+
? TEvent extends { type: string }
|
|
75
|
+
? Omit<TEvent, "partial" | "message" | "error">
|
|
76
|
+
: never
|
|
77
|
+
: never;
|
|
78
|
+
|
|
79
|
+
export interface AgentWireCompactMessageUpdatePayload {
|
|
80
|
+
event_type: "message_update";
|
|
81
|
+
/** Compact RPC opt-in payload: delta-only update plus minimal routing metadata. */
|
|
82
|
+
compact: true;
|
|
83
|
+
message_id: string | null;
|
|
84
|
+
content_index: number | null;
|
|
85
|
+
assistantMessageEvent: AgentWireCompactAssistantMessageEvent;
|
|
86
|
+
/** Full message checkpoint, snapshotted synchronously when this frame is enqueued. */
|
|
87
|
+
checkpoint_message?: Extract<AgentSessionEvent, { type: "message_update" }>["message"];
|
|
88
|
+
checkpoint_reason?: "periodic";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type AgentWireEventFramePayload = AgentWireEventPayload | AgentWireCompactMessageUpdatePayload;
|
|
71
92
|
|
|
72
93
|
/**
|
|
73
94
|
* Bounded observed-signal vocabulary surfaced to owner control planes. Mirrors
|
|
@@ -146,3 +167,4 @@ export interface AgentWireFrameEnvelope<TType extends AgentWireFrameType = Agent
|
|
|
146
167
|
|
|
147
168
|
/** An `AgentSessionEvent` serialized into a versioned wire frame. */
|
|
148
169
|
export type AgentWireEventFrame = AgentWireFrameEnvelope<"event", AgentWireEventPayload>;
|
|
170
|
+
export type AgentWireCompactEventFrame = AgentWireFrameEnvelope<"event", AgentWireEventFramePayload>;
|
|
@@ -12,6 +12,9 @@ import { randomUUID } from "node:crypto";
|
|
|
12
12
|
import type { AgentSessionEvent } from "../../../session/agent-session";
|
|
13
13
|
import {
|
|
14
14
|
AGENT_WIRE_PROTOCOL_VERSION,
|
|
15
|
+
type AgentWireCompactAssistantMessageEvent,
|
|
16
|
+
type AgentWireCompactEventFrame,
|
|
17
|
+
type AgentWireCompactMessageUpdatePayload,
|
|
15
18
|
type AgentWireEventFrame,
|
|
16
19
|
type AgentWireEventPayload,
|
|
17
20
|
type AgentWireEventType,
|
|
@@ -19,6 +22,26 @@ import {
|
|
|
19
22
|
type AgentWireFrameType,
|
|
20
23
|
} from "./event-contract";
|
|
21
24
|
|
|
25
|
+
export const AGENT_WIRE_COMPACT_MESSAGE_UPDATE_CHECKPOINT_INTERVAL = 32;
|
|
26
|
+
|
|
27
|
+
function recordObject(value: unknown): Record<string, unknown> | undefined {
|
|
28
|
+
return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function messageIdOf(message: unknown): string | null {
|
|
32
|
+
const id = recordObject(message)?.id;
|
|
33
|
+
return typeof id === "string" ? id : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function contentIndexOf(assistantMessageEvent: unknown): number | null {
|
|
37
|
+
const contentIndex = recordObject(assistantMessageEvent)?.contentIndex;
|
|
38
|
+
return typeof contentIndex === "number" && Number.isInteger(contentIndex) ? contentIndex : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function snapshotMessage<T>(message: T): T {
|
|
42
|
+
return structuredClone(message);
|
|
43
|
+
}
|
|
44
|
+
|
|
22
45
|
function assertNever(value: never): never {
|
|
23
46
|
throw new Error(`Unhandled AgentSessionEvent variant: ${JSON.stringify(value)}`);
|
|
24
47
|
}
|
|
@@ -123,6 +146,65 @@ export function toAgentWireEventFrame(
|
|
|
123
146
|
export function toAgentWireEventPayload(event: AgentSessionEvent): AgentWireEventPayload {
|
|
124
147
|
return { event_type: agentSessionEventType(event), event };
|
|
125
148
|
}
|
|
149
|
+
export function sanitizeAssistantMessageEventForCompact(
|
|
150
|
+
assistantMessageEvent: Extract<AgentSessionEvent, { type: "message_update" }>["assistantMessageEvent"],
|
|
151
|
+
): AgentWireCompactAssistantMessageEvent {
|
|
152
|
+
const {
|
|
153
|
+
partial: _partial,
|
|
154
|
+
message: _message,
|
|
155
|
+
error: _error,
|
|
156
|
+
...deltaOnly
|
|
157
|
+
} = assistantMessageEvent as Record<string, unknown>;
|
|
158
|
+
return deltaOnly as AgentWireCompactAssistantMessageEvent;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface AgentWireCompactMessageUpdateOptions {
|
|
162
|
+
checkpointInterval?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Stateful compact event serializer for opt-in RPC clients.
|
|
167
|
+
*
|
|
168
|
+
* Only `message_update` changes shape: it carries the immutable provider delta
|
|
169
|
+
* plus message/content identifiers, with periodic full-message checkpoints that
|
|
170
|
+
* are cloned synchronously before the caller returns to the event loop. All other
|
|
171
|
+
* event variants remain canonical full event frames so legacy bridge/RPC behavior
|
|
172
|
+
* and terminal `message_end` reconstruction are unchanged.
|
|
173
|
+
*/
|
|
174
|
+
export class AgentWireCompactEventEncoder {
|
|
175
|
+
readonly #sequencer: AgentWireFrameSequencer;
|
|
176
|
+
readonly #checkpointInterval: number;
|
|
177
|
+
#messageUpdateCount = 0;
|
|
178
|
+
|
|
179
|
+
constructor(sequencer: AgentWireFrameSequencer, options: AgentWireCompactMessageUpdateOptions = {}) {
|
|
180
|
+
this.#sequencer = sequencer;
|
|
181
|
+
this.#checkpointInterval = options.checkpointInterval ?? AGENT_WIRE_COMPACT_MESSAGE_UPDATE_CHECKPOINT_INTERVAL;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
frame(event: AgentSessionEvent): AgentWireCompactEventFrame {
|
|
185
|
+
if (event.type !== "message_update") return toAgentWireEventFrame(event, this.#sequencer);
|
|
186
|
+
this.#messageUpdateCount += 1;
|
|
187
|
+
const payload: AgentWireCompactMessageUpdatePayload = {
|
|
188
|
+
event_type: "message_update",
|
|
189
|
+
compact: true,
|
|
190
|
+
message_id: messageIdOf(event.message),
|
|
191
|
+
content_index: contentIndexOf(event.assistantMessageEvent),
|
|
192
|
+
assistantMessageEvent: sanitizeAssistantMessageEventForCompact(event.assistantMessageEvent),
|
|
193
|
+
};
|
|
194
|
+
if (this.#checkpointInterval > 0 && this.#messageUpdateCount % this.#checkpointInterval === 0) {
|
|
195
|
+
payload.checkpoint_message = snapshotMessage(event.message);
|
|
196
|
+
payload.checkpoint_reason = "periodic";
|
|
197
|
+
}
|
|
198
|
+
return this.#sequencer.next("event", payload);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function toAgentWireCompactEventFrame(
|
|
203
|
+
event: AgentSessionEvent,
|
|
204
|
+
encoder: AgentWireCompactEventEncoder,
|
|
205
|
+
): AgentWireCompactEventFrame {
|
|
206
|
+
return encoder.frame(event);
|
|
207
|
+
}
|
|
126
208
|
|
|
127
209
|
/** Back-compat alias for {@link toAgentWireEventFrame}. */
|
|
128
210
|
export const toBridgeEventFrame = toAgentWireEventFrame;
|
|
@@ -47,6 +47,7 @@ const RPC_COMMAND_SCOPE_REGISTRY: Record<RpcCommandType, BridgeCommandScope> = {
|
|
|
47
47
|
set_host_tools: "host_tools",
|
|
48
48
|
set_host_uri_schemes: "host_uri",
|
|
49
49
|
get_pending_workflow_gates: "message:read",
|
|
50
|
+
set_capabilities: "control",
|
|
50
51
|
set_model: "model",
|
|
51
52
|
cycle_model: "model",
|
|
52
53
|
get_available_models: "model",
|
package/src/modes/types.ts
CHANGED
|
@@ -216,6 +216,7 @@ export interface InteractiveModeContext {
|
|
|
216
216
|
handleDumpCommand(): void;
|
|
217
217
|
handleDebugTranscriptCommand(): Promise<void>;
|
|
218
218
|
handleClearCommand(): Promise<void>;
|
|
219
|
+
handleContextClearCommand(): Promise<void>;
|
|
219
220
|
handleDropCommand(): Promise<void>;
|
|
220
221
|
handleForkCommand(): Promise<void>;
|
|
221
222
|
handleBashCommand(command: string, excludeFromContext?: boolean): Promise<void>;
|
|
@@ -23,6 +23,7 @@ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string
|
|
|
23
23
|
"|-----|--------|",
|
|
24
24
|
"| `Enter` | Send / queue while busy |",
|
|
25
25
|
`| \`${appKey(bindings, "app.message.queue")}\` | Queue message for next turn |`,
|
|
26
|
+
`| \`${appKey(bindings, "app.message.dequeue")}\` | Select queued message to edit |`,
|
|
26
27
|
"| `Shift+Enter` / `Ctrl+J` | New line |",
|
|
27
28
|
"| `Ctrl+W` / `Option+Backspace` | Delete word backwards |",
|
|
28
29
|
"| `Ctrl+U` | Delete to start of line |",
|
|
@@ -2,9 +2,9 @@ import type { AgentMessage } from "@sayknow-cli/agent-core";
|
|
|
2
2
|
import type { AssistantMessage, ImageContent, Message } from "@sayknow-cli/ai";
|
|
3
3
|
import { type Component, Spacer, Text, TruncatedText } from "@sayknow-cli/tui";
|
|
4
4
|
import { settings } from "../../config/settings";
|
|
5
|
-
import { tMessage } from "../../i18n";
|
|
6
5
|
import { resolveSubskillActivationForSkillInvocation } from "../../extensibility/skc-plugins";
|
|
7
6
|
import { buildSkillPromptMessage, parseSkillInvocations } from "../../extensibility/skills";
|
|
7
|
+
import { tMessage } from "../../i18n";
|
|
8
8
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
9
9
|
import { BashExecutionComponent } from "../../modes/components/bash-execution";
|
|
10
10
|
import { BranchSummaryMessageComponent } from "../../modes/components/branch-summary-message";
|
|
@@ -37,6 +37,19 @@ interface RenderInitialMessagesOptions {
|
|
|
37
37
|
preserveExistingChat?: boolean;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
export function argsWithPartialJson(args: unknown, partialJson: unknown): unknown {
|
|
41
|
+
if (typeof partialJson !== "string" || !args || typeof args !== "object" || Array.isArray(args)) return args;
|
|
42
|
+
// Non-enumerable so the transient streaming buffer reaches renderers via direct
|
|
43
|
+
// property read but never serializes into persisted/wire message content.
|
|
44
|
+
Object.defineProperty(args, "__partialJson", {
|
|
45
|
+
value: partialJson,
|
|
46
|
+
enumerable: false,
|
|
47
|
+
configurable: true,
|
|
48
|
+
writable: true,
|
|
49
|
+
});
|
|
50
|
+
return args;
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
type QueuedMessages = {
|
|
41
54
|
steering: string[];
|
|
42
55
|
followUp: string[];
|
|
@@ -394,10 +407,10 @@ export class UiHelpers {
|
|
|
394
407
|
|
|
395
408
|
readGroup = null;
|
|
396
409
|
const tool = this.ctx.session.getToolByName(content.name);
|
|
397
|
-
const renderArgs =
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
410
|
+
const renderArgs = argsWithPartialJson(
|
|
411
|
+
content.arguments,
|
|
412
|
+
"partialJson" in content ? content.partialJson : undefined,
|
|
413
|
+
);
|
|
401
414
|
const component = new ToolExecutionComponent(
|
|
402
415
|
content.name,
|
|
403
416
|
renderArgs,
|
|
@@ -605,8 +618,8 @@ export class UiHelpers {
|
|
|
605
618
|
const queuedText = theme.fg("dim", `${entry.label}: ${entry.message}`);
|
|
606
619
|
this.ctx.pendingMessagesContainer.addChild(new TruncatedText(queuedText, 1, 0));
|
|
607
620
|
}
|
|
608
|
-
const dequeueKey = this.ctx.keybindings.getDisplayString("app.message.dequeue") || "Alt+Up";
|
|
609
|
-
const hintText = theme.fg("dim", `${theme.tree.hook} ${dequeueKey} to edit`);
|
|
621
|
+
const dequeueKey = this.ctx.keybindings.getDisplayString("app.message.dequeue") || "Alt+Up/Alt+Down";
|
|
622
|
+
const hintText = theme.fg("dim", `${theme.tree.hook} ${dequeueKey} to select/edit/reorder`);
|
|
610
623
|
this.ctx.pendingMessagesContainer.addChild(new TruncatedText(hintText, 1, 0));
|
|
611
624
|
}
|
|
612
625
|
}
|
|
@@ -38,13 +38,24 @@ export function getNotificationConfig(settings: Settings): NotificationConfig {
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export function hasNonBlankValue(value: string | undefined): boolean {
|
|
42
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Is Telegram configured with usable non-blank boundary credentials? */
|
|
46
|
+
export function isTelegramConfigured(
|
|
47
|
+
cfg: NotificationConfig,
|
|
48
|
+
): cfg is NotificationConfig & { botToken: string; chatId: string } {
|
|
49
|
+
return cfg.enabled && hasNonBlankValue(cfg.botToken) && hasNonBlankValue(cfg.chatId);
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
/** Is global config sufficient for auto-on (enabled + at least one configured adapter)? */
|
|
42
53
|
export function isGloballyConfigured(cfg: NotificationConfig): boolean {
|
|
43
54
|
return (
|
|
44
55
|
cfg.enabled &&
|
|
45
|
-
((
|
|
46
|
-
(
|
|
47
|
-
(
|
|
56
|
+
(isTelegramConfigured(cfg) ||
|
|
57
|
+
(hasNonBlankValue(cfg.discord.botToken) && hasNonBlankValue(cfg.discord.channelId)) ||
|
|
58
|
+
(hasNonBlankValue(cfg.slack.botToken) && hasNonBlankValue(cfg.slack.channelId)))
|
|
48
59
|
);
|
|
49
60
|
}
|
|
50
61
|
|
|
@@ -52,7 +63,14 @@ export function isGloballyConfigured(cfg: NotificationConfig): boolean {
|
|
|
52
63
|
export function shouldRegisterNotificationsExtension(input: {
|
|
53
64
|
env: NodeJS.ProcessEnv;
|
|
54
65
|
cfg?: NotificationConfig;
|
|
66
|
+
/** Task recursion depth; helper/subagent sessions must not spawn remote surfaces. */
|
|
67
|
+
taskDepth?: number;
|
|
68
|
+
/** Parent subagent id/prefix; present for helper/subagent sessions even when depth is omitted. */
|
|
69
|
+
parentTaskPrefix?: string;
|
|
70
|
+
/** Role-agent type/name; present for task sessions even if depth metadata is lost. */
|
|
71
|
+
currentAgentType?: string;
|
|
55
72
|
}): boolean {
|
|
73
|
+
if ((input.taskDepth ?? 0) > 0 || input.parentTaskPrefix || input.currentAgentType) return false;
|
|
56
74
|
if (input.env.SKC_NOTIFICATIONS === "0") return false;
|
|
57
75
|
if (input.env.SKC_NOTIFICATIONS === "1" || input.env.SKC_NOTIFICATIONS_TOKEN) return true;
|
|
58
76
|
return input.cfg ? isGloballyConfigured(input.cfg) : false;
|
|
@@ -81,6 +99,7 @@ export function isSessionNotificationsEnabled(input: {
|
|
|
81
99
|
/** Mask a bot token for display: first 4 chars + "…" + "(len N)"; "(unset)" when undefined/empty. Never reveal full token. */
|
|
82
100
|
export function maskToken(token: string | undefined): string {
|
|
83
101
|
if (!token) return "(unset)";
|
|
102
|
+
if (token.length <= 4) return `…(len ${token.length})`;
|
|
84
103
|
return `${token.slice(0, 4)}…(len ${token.length})`;
|
|
85
104
|
}
|
|
86
105
|
|
|
@@ -112,7 +131,8 @@ export interface RedactableAction {
|
|
|
112
131
|
* When redact is false, return the action unchanged.
|
|
113
132
|
*
|
|
114
133
|
* Redaction still applies to streamed content frames (turn_stream, context_update,
|
|
115
|
-
* image_attachment) which are suppressed at their emit sites, not here.
|
|
134
|
+
* image_attachment) which are suppressed at their emit sites, not here. Explicit
|
|
135
|
+
* `telegram_send` file attachments are rejected before the file is read or forwarded.
|
|
116
136
|
*/
|
|
117
137
|
export function buildRedactedAction(
|
|
118
138
|
action: RedactableAction,
|
|
@@ -123,6 +143,6 @@ export function buildRedactedAction(
|
|
|
123
143
|
// Asks stay fully readable/answerable even under redaction.
|
|
124
144
|
if (action.kind === "ask") return action;
|
|
125
145
|
|
|
126
|
-
const { summary: _summary, question: _question, ...base } = action;
|
|
146
|
+
const { summary: _summary, question: _question, options: _options, ...base } = action;
|
|
127
147
|
return base;
|
|
128
148
|
}
|
|
@@ -7,6 +7,7 @@ export interface DaemonPaths {
|
|
|
7
7
|
roots: string;
|
|
8
8
|
steal: string;
|
|
9
9
|
aliases: string;
|
|
10
|
+
seenUpdates: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export function daemonPaths(agentDir: string): DaemonPaths {
|
|
@@ -18,5 +19,6 @@ export function daemonPaths(agentDir: string): DaemonPaths {
|
|
|
18
19
|
roots: path.join(dir, "telegram-daemon.roots.json"),
|
|
19
20
|
steal: path.join(dir, "telegram-daemon.steal"),
|
|
20
21
|
aliases: path.join(dir, "telegram-callback-aliases.json"),
|
|
22
|
+
seenUpdates: path.join(dir, "telegram-seen-updates.json"),
|
|
21
23
|
};
|
|
22
24
|
}
|