@gajae-code/coding-agent 0.3.2 → 0.4.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 +32 -0
- package/dist/types/config/model-registry.d.ts +17 -10
- package/dist/types/config/models-config-schema.d.ts +37 -0
- package/dist/types/config/settings-schema.d.ts +5 -0
- package/dist/types/edit/diff.d.ts +16 -0
- package/dist/types/edit/modes/replace.d.ts +7 -0
- package/dist/types/extensibility/gjc-plugins/activation.d.ts +14 -0
- package/dist/types/extensibility/gjc-plugins/index.d.ts +9 -0
- package/dist/types/extensibility/gjc-plugins/injection.d.ts +31 -0
- package/dist/types/extensibility/gjc-plugins/loader.d.ts +3 -0
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +8 -0
- package/dist/types/extensibility/gjc-plugins/schema.d.ts +3 -0
- package/dist/types/extensibility/gjc-plugins/state.d.ts +9 -0
- package/dist/types/extensibility/gjc-plugins/tools.d.ts +8 -0
- package/dist/types/extensibility/gjc-plugins/types.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/validation.d.ts +4 -0
- package/dist/types/extensibility/skills.d.ts +9 -1
- package/dist/types/gjc-runtime/state-runtime.d.ts +22 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -2
- package/dist/types/harness-control-plane/storage.d.ts +7 -0
- package/dist/types/lsp/client.d.ts +1 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +2 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +2 -2
- package/dist/types/modes/rpc/rpc-client.d.ts +9 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +179 -2
- package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +57 -0
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +16 -1
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +47 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +7 -0
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +11 -1
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +3 -1
- package/dist/types/modes/shared/agent-wire/responses.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +27 -0
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +68 -0
- package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +161 -0
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +61 -0
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +114 -0
- package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +39 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/runtime-mcp/transports/stdio.d.ts +0 -4
- package/dist/types/sdk.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +10 -0
- package/dist/types/session/blob-store.d.ts +17 -0
- package/dist/types/session/messages.d.ts +3 -0
- package/dist/types/session/session-storage.d.ts +6 -0
- package/dist/types/skill-state/active-state.d.ts +13 -0
- package/dist/types/thinking.d.ts +3 -2
- package/dist/types/tools/index.d.ts +3 -0
- package/package.json +9 -7
- package/src/cli.ts +14 -0
- package/src/commands/harness.ts +192 -7
- package/src/commands/ultragoal.ts +1 -21
- package/src/config/model-equivalence.ts +1 -1
- package/src/config/model-registry.ts +32 -5
- package/src/config/models-config-schema.ts +7 -2
- package/src/config/settings-schema.ts +4 -1
- package/src/discovery/claude-plugins.ts +25 -5
- package/src/edit/diff.ts +64 -1
- package/src/edit/modes/replace.ts +60 -2
- package/src/extensibility/gjc-plugins/activation.ts +87 -0
- package/src/extensibility/gjc-plugins/index.ts +9 -0
- package/src/extensibility/gjc-plugins/injection.ts +114 -0
- package/src/extensibility/gjc-plugins/loader.ts +131 -0
- package/src/extensibility/gjc-plugins/paths.ts +66 -0
- package/src/extensibility/gjc-plugins/schema.ts +79 -0
- package/src/extensibility/gjc-plugins/state.ts +29 -0
- package/src/extensibility/gjc-plugins/tools.ts +47 -0
- package/src/extensibility/gjc-plugins/types.ts +97 -0
- package/src/extensibility/gjc-plugins/validation.ts +76 -0
- package/src/extensibility/skills.ts +39 -7
- package/src/gjc-runtime/state-runtime.ts +93 -2
- package/src/gjc-runtime/state-writer.ts +17 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +76 -121
- package/src/gjc-runtime/workflow-manifest.generated.json +5 -0
- package/src/gjc-runtime/workflow-manifest.ts +2 -2
- package/src/harness-control-plane/storage.ts +144 -2
- package/src/hashline/hash.ts +23 -0
- package/src/hooks/skill-state.ts +2 -0
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/lsp/client.ts +7 -0
- package/src/modes/acp/acp-agent.ts +25 -2
- package/src/modes/bridge/bridge-mode.ts +124 -2
- package/src/modes/controllers/input-controller.ts +14 -2
- package/src/modes/prompt-action-autocomplete.ts +49 -10
- package/src/modes/rpc/rpc-client.ts +57 -3
- package/src/modes/rpc/rpc-mode.ts +67 -0
- package/src/modes/rpc/rpc-types.ts +224 -2
- package/src/modes/shared/agent-wire/approval-gate.ts +151 -0
- package/src/modes/shared/agent-wire/command-dispatch.ts +97 -4
- package/src/modes/shared/agent-wire/command-validation.ts +25 -1
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +222 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +13 -0
- package/src/modes/shared/agent-wire/handshake.ts +43 -3
- package/src/modes/shared/agent-wire/protocol.ts +7 -0
- package/src/modes/shared/agent-wire/responses.ts +2 -2
- package/src/modes/shared/agent-wire/scopes.ts +2 -0
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +341 -0
- package/src/modes/shared/agent-wire/unattended-audit.ts +175 -0
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +406 -0
- package/src/modes/shared/agent-wire/unattended-session.ts +180 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +324 -0
- package/src/modes/shared/agent-wire/workflow-gate-schema.ts +331 -0
- package/src/modes/theme/theme.ts +6 -0
- package/src/runtime-mcp/client.ts +7 -4
- package/src/runtime-mcp/manager.ts +45 -13
- package/src/runtime-mcp/transports/http.ts +40 -14
- package/src/runtime-mcp/transports/stdio.ts +11 -10
- package/src/sdk.ts +47 -0
- package/src/session/agent-session.ts +211 -2
- package/src/session/blob-store.ts +84 -0
- package/src/session/messages.ts +3 -0
- package/src/session/session-manager.ts +390 -33
- package/src/session/session-storage.ts +26 -0
- package/src/setup/provider-onboarding.ts +2 -2
- package/src/skill-state/active-state.ts +89 -1
- package/src/task/discovery.ts +7 -1
- package/src/task/executor.ts +16 -2
- package/src/thinking.ts +8 -2
- package/src/tools/ask.ts +39 -9
- package/src/tools/index.ts +3 -0
- package/src/tools/skill.ts +15 -3
- package/src/utils/edit-mode.ts +1 -1
|
@@ -163,6 +163,10 @@ import type {
|
|
|
163
163
|
} from "../extensibility/extensions";
|
|
164
164
|
import type { CompactOptions, ContextUsage } from "../extensibility/extensions/types";
|
|
165
165
|
import { ExtensionToolWrapper } from "../extensibility/extensions/wrapper";
|
|
166
|
+
import type { LoadedSubskillActivation } from "../extensibility/gjc-plugins";
|
|
167
|
+
import { resolveCurrentPhaseForParent } from "../extensibility/gjc-plugins/injection";
|
|
168
|
+
import { readActiveSubskillsForParent, toActiveSubskillEntry } from "../extensibility/gjc-plugins/state";
|
|
169
|
+
import { loadActiveSubskillTools } from "../extensibility/gjc-plugins/tools";
|
|
166
170
|
import type { HookCommandContext } from "../extensibility/hooks/types";
|
|
167
171
|
import type { Skill, SkillWarning } from "../extensibility/skills";
|
|
168
172
|
import { expandSlashCommand, type FileSlashCommand } from "../extensibility/slash-commands";
|
|
@@ -174,7 +178,9 @@ import type { Goal, GoalModeState } from "../goals/state";
|
|
|
174
178
|
import type { HindsightSessionState } from "../hindsight/state";
|
|
175
179
|
import { ensureWorkflowSkillActivationState } from "../hooks/skill-state";
|
|
176
180
|
import { type LocalProtocolOptions, resolveLocalUrlToPath } from "../internal-urls";
|
|
181
|
+
import { shutdownAll as shutdownAllLspClients } from "../lsp/client";
|
|
177
182
|
import { resolveMemoryBackend } from "../memory-backend";
|
|
183
|
+
import type { WorkflowGateEmitter } from "../modes/shared/agent-wire/unattended-session";
|
|
178
184
|
import { getCurrentThemeName, theme } from "../modes/theme/theme";
|
|
179
185
|
import type { PlanModeState } from "../plan-mode/state";
|
|
180
186
|
import autoContinuePrompt from "../prompts/system/auto-continue.md" with { type: "text" };
|
|
@@ -197,9 +203,14 @@ import {
|
|
|
197
203
|
isMCPToolName,
|
|
198
204
|
selectDiscoverableMCPToolNamesByServer,
|
|
199
205
|
} from "../runtime-mcp/discoverable-tool-metadata";
|
|
206
|
+
import { MCPManager } from "../runtime-mcp/manager";
|
|
200
207
|
import { deobfuscateSessionContext, type SecretObfuscator } from "../secrets/obfuscator";
|
|
201
208
|
import { formatNoCredentialOnboardingError, formatNoModelOnboardingError } from "../setup/model-onboarding-guidance";
|
|
202
|
-
import {
|
|
209
|
+
import {
|
|
210
|
+
isCanonicalGjcWorkflowSkill,
|
|
211
|
+
readVisibleSkillActiveState,
|
|
212
|
+
syncSkillActiveState,
|
|
213
|
+
} from "../skill-state/active-state";
|
|
203
214
|
import { assertDeepInterviewMutationAllowed } from "../skill-state/deep-interview-mutation-guard";
|
|
204
215
|
import { invalidateHostMetadata } from "../ssh/connection-manager";
|
|
205
216
|
import { resolveThinkingLevelForModel, toReasoningEffort } from "../thinking";
|
|
@@ -209,9 +220,11 @@ import {
|
|
|
209
220
|
type DiscoverableTool,
|
|
210
221
|
type DiscoverableToolSearchIndex,
|
|
211
222
|
} from "../tool-discovery/tool-index";
|
|
223
|
+
import type { ToolSession } from "../tools";
|
|
224
|
+
import { AskTool } from "../tools/ask";
|
|
212
225
|
import { assertEditableFile } from "../tools/auto-generated-guard";
|
|
213
226
|
import type { CheckpointState } from "../tools/checkpoint";
|
|
214
|
-
import { outputMeta } from "../tools/output-meta";
|
|
227
|
+
import { outputMeta, wrapToolWithMetaNotice } from "../tools/output-meta";
|
|
215
228
|
import { normalizeLocalScheme, resolveToCwd } from "../tools/path-utils";
|
|
216
229
|
import { getLatestTodoPhasesFromEntries, type TodoItem, type TodoPhase } from "../tools/todo-write";
|
|
217
230
|
import { ToolAbortError, ToolError } from "../tools/tool-errors";
|
|
@@ -337,6 +350,8 @@ export interface AgentSessionConfig {
|
|
|
337
350
|
taskDepth?: number;
|
|
338
351
|
/** Tool registry for LSP and settings */
|
|
339
352
|
toolRegistry?: Map<string, AgentTool>;
|
|
353
|
+
/** Tool-session factory context used to lazily attach workflow-gate-only tools. */
|
|
354
|
+
workflowGateToolSession?: ToolSession;
|
|
340
355
|
/** Current session pre-LLM message transform pipeline */
|
|
341
356
|
transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
|
|
342
357
|
/** Provider payload hook used by the active session request path */
|
|
@@ -844,6 +859,7 @@ export class AgentSession {
|
|
|
844
859
|
#scheduledHiddenNextTurnGeneration: number | undefined = undefined;
|
|
845
860
|
#planModeState: PlanModeState | undefined;
|
|
846
861
|
#goalModeState: GoalModeState | undefined;
|
|
862
|
+
#workflowGateEmitter: WorkflowGateEmitter | undefined;
|
|
847
863
|
#goalRuntime: GoalRuntime;
|
|
848
864
|
#goalTurnCounter = 0;
|
|
849
865
|
#planReferenceSent = false;
|
|
@@ -923,6 +939,7 @@ export class AgentSession {
|
|
|
923
939
|
|
|
924
940
|
// Tool registry and prompt builder for extensions
|
|
925
941
|
#toolRegistry: Map<string, AgentTool>;
|
|
942
|
+
#workflowGateToolSession: ToolSession | undefined;
|
|
926
943
|
#transformContext: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
|
|
927
944
|
#onPayload: SimpleStreamOptions["onPayload"] | undefined;
|
|
928
945
|
#onResponse: SimpleStreamOptions["onResponse"] | undefined;
|
|
@@ -950,6 +967,8 @@ export class AgentSession {
|
|
|
950
967
|
#discoverableToolSearchIndex: DiscoverableToolSearchIndex | null = null;
|
|
951
968
|
#selectedDiscoveredToolNames = new Set<string>();
|
|
952
969
|
#rpcHostToolNames = new Set<string>();
|
|
970
|
+
#gjcSubskillToolNames = new Set<string>();
|
|
971
|
+
#gjcSubskillToolSignature: string | undefined;
|
|
953
972
|
#defaultSelectedMCPServerNames = new Set<string>();
|
|
954
973
|
#defaultSelectedMCPToolNames = new Set<string>();
|
|
955
974
|
#sessionDefaultSelectedMCPToolNames = new Map<string, string[]>();
|
|
@@ -1100,6 +1119,7 @@ export class AgentSession {
|
|
|
1100
1119
|
}
|
|
1101
1120
|
this.#validateRetryFallbackChains();
|
|
1102
1121
|
this.#toolRegistry = config.toolRegistry ?? new Map();
|
|
1122
|
+
this.#workflowGateToolSession = config.workflowGateToolSession;
|
|
1103
1123
|
this.#requestedToolNames = config.requestedToolNames;
|
|
1104
1124
|
this.#transformContext = config.transformContext ?? (messages => messages);
|
|
1105
1125
|
this.#onPayload = config.onPayload;
|
|
@@ -3112,6 +3132,14 @@ export class AgentSession {
|
|
|
3112
3132
|
AsyncJobManager.setInstance(undefined);
|
|
3113
3133
|
}
|
|
3114
3134
|
}
|
|
3135
|
+
const mcpManager = MCPManager.instance();
|
|
3136
|
+
if (mcpManager) {
|
|
3137
|
+
await mcpManager.disconnectAll();
|
|
3138
|
+
if (MCPManager.instance() === mcpManager) {
|
|
3139
|
+
MCPManager.setInstance(undefined);
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
await shutdownAllLspClients();
|
|
3115
3143
|
const pythonExecutionsSettled = await this.#prepareEvalExecutionsForDispose();
|
|
3116
3144
|
if (!pythonExecutionsSettled) {
|
|
3117
3145
|
logger.warn(
|
|
@@ -3942,6 +3970,123 @@ export class AgentSession {
|
|
|
3942
3970
|
);
|
|
3943
3971
|
}
|
|
3944
3972
|
|
|
3973
|
+
async #hasActiveGjcSubskillTools(parent: string, sessionId: string | undefined): Promise<boolean> {
|
|
3974
|
+
if (!parent.trim()) return false;
|
|
3975
|
+
const cwd = this.sessionManager.getCwd();
|
|
3976
|
+
const phase = await resolveCurrentPhaseForParent({ cwd, sessionId, parent });
|
|
3977
|
+
const entries = await readActiveSubskillsForParent({ cwd, sessionId, parent, phase });
|
|
3978
|
+
return entries.some(entry => (entry.toolPaths ?? []).some(toolPath => toolPath.trim().length > 0));
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3981
|
+
#getCustomToolContext(): CustomToolContext {
|
|
3982
|
+
return {
|
|
3983
|
+
sessionManager: this.sessionManager,
|
|
3984
|
+
modelRegistry: this.#modelRegistry,
|
|
3985
|
+
model: this.model,
|
|
3986
|
+
isIdle: () => !this.isStreaming,
|
|
3987
|
+
hasQueuedMessages: () => this.queuedMessageCount > 0,
|
|
3988
|
+
abort: () => {
|
|
3989
|
+
this.agent.abort();
|
|
3990
|
+
},
|
|
3991
|
+
};
|
|
3992
|
+
}
|
|
3993
|
+
|
|
3994
|
+
#computeGjcSubskillToolSignature(tools: CustomTool[]): string {
|
|
3995
|
+
return tools
|
|
3996
|
+
.map(tool => `${tool.name}\u0000${tool.description}\u0000${JSON.stringify(tool.parameters)}`)
|
|
3997
|
+
.sort()
|
|
3998
|
+
.join("\u0001");
|
|
3999
|
+
}
|
|
4000
|
+
|
|
4001
|
+
/**
|
|
4002
|
+
* Refresh plugin sub-skill tools after workflow/sub-skill activation or phase changes.
|
|
4003
|
+
*/
|
|
4004
|
+
async refreshGjcSubskillTools(): Promise<void> {
|
|
4005
|
+
const activeState = await readVisibleSkillActiveState(
|
|
4006
|
+
this.sessionManager.getCwd(),
|
|
4007
|
+
this.sessionManager.getSessionId(),
|
|
4008
|
+
);
|
|
4009
|
+
const activeSkill =
|
|
4010
|
+
this.#activeSkillState?.skill ??
|
|
4011
|
+
activeState?.skill ??
|
|
4012
|
+
activeState?.active_skills?.find(entry => entry.active !== false)?.skill;
|
|
4013
|
+
const parent = activeSkill?.trim();
|
|
4014
|
+
if (!parent) {
|
|
4015
|
+
if (this.#gjcSubskillToolNames.size === 0) return;
|
|
4016
|
+
const previousGjcSubskillToolNames = new Set(this.#gjcSubskillToolNames);
|
|
4017
|
+
const previousActiveToolNames = this.getActiveToolNames();
|
|
4018
|
+
for (const name of previousGjcSubskillToolNames) {
|
|
4019
|
+
this.#toolRegistry.delete(name);
|
|
4020
|
+
}
|
|
4021
|
+
this.#gjcSubskillToolNames.clear();
|
|
4022
|
+
this.#invalidateDiscoveryCaches();
|
|
4023
|
+
await this.#applyActiveToolsByName(
|
|
4024
|
+
previousActiveToolNames.filter(name => !previousGjcSubskillToolNames.has(name)),
|
|
4025
|
+
);
|
|
4026
|
+
return;
|
|
4027
|
+
}
|
|
4028
|
+
|
|
4029
|
+
const cwd = this.sessionManager.getCwd();
|
|
4030
|
+
const sessionId =
|
|
4031
|
+
this.#activeSkillState?.sessionId ?? activeState?.session_id ?? this.sessionManager.getSessionId();
|
|
4032
|
+
if (this.#gjcSubskillToolNames.size === 0 && !(await this.#hasActiveGjcSubskillTools(parent, sessionId))) return;
|
|
4033
|
+
|
|
4034
|
+
const phase = await resolveCurrentPhaseForParent({ cwd, sessionId, parent });
|
|
4035
|
+
const reservedToolNames = Array.from(this.#toolRegistry.keys()).filter(
|
|
4036
|
+
name => !this.#gjcSubskillToolNames.has(name),
|
|
4037
|
+
);
|
|
4038
|
+
const customTools = await loadActiveSubskillTools({ cwd, sessionId, parent, phase, reservedToolNames });
|
|
4039
|
+
const nextToolNames = customTools.map(tool => tool.name);
|
|
4040
|
+
const uniqueToolNames = new Set(nextToolNames);
|
|
4041
|
+
if (uniqueToolNames.size !== nextToolNames.length) {
|
|
4042
|
+
throw new Error("GJC sub-skill tool names must be unique");
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
const previousGjcSubskillToolNames = new Set(this.#gjcSubskillToolNames);
|
|
4046
|
+
const nextSignature = this.#computeGjcSubskillToolSignature(customTools);
|
|
4047
|
+
if (this.#gjcSubskillToolSignature === nextSignature) {
|
|
4048
|
+
return;
|
|
4049
|
+
}
|
|
4050
|
+
|
|
4051
|
+
const previousActiveToolNames = this.getActiveToolNames();
|
|
4052
|
+
for (const name of previousGjcSubskillToolNames) {
|
|
4053
|
+
this.#toolRegistry.delete(name);
|
|
4054
|
+
}
|
|
4055
|
+
this.#gjcSubskillToolNames.clear();
|
|
4056
|
+
this.#gjcSubskillToolSignature = undefined;
|
|
4057
|
+
|
|
4058
|
+
const getCustomToolContext = () => this.#getCustomToolContext();
|
|
4059
|
+
for (const customTool of customTools) {
|
|
4060
|
+
const wrapped = CustomToolAdapter.wrap(customTool, getCustomToolContext) as AgentTool;
|
|
4061
|
+
const finalTool = (
|
|
4062
|
+
this.#extensionRunner ? new ExtensionToolWrapper(wrapped, this.#extensionRunner) : wrapped
|
|
4063
|
+
) as AgentTool;
|
|
4064
|
+
this.#toolRegistry.set(finalTool.name, finalTool);
|
|
4065
|
+
this.#gjcSubskillToolNames.add(finalTool.name);
|
|
4066
|
+
}
|
|
4067
|
+
this.#gjcSubskillToolSignature = nextSignature;
|
|
4068
|
+
|
|
4069
|
+
this.#invalidateDiscoveryCaches();
|
|
4070
|
+
const activeNonGjcSubskillToolNames = previousActiveToolNames.filter(
|
|
4071
|
+
name => !previousGjcSubskillToolNames.has(name),
|
|
4072
|
+
);
|
|
4073
|
+
const preservedGjcSubskillToolNames = previousActiveToolNames.filter(
|
|
4074
|
+
name => previousGjcSubskillToolNames.has(name) && this.#gjcSubskillToolNames.has(name),
|
|
4075
|
+
);
|
|
4076
|
+
const autoActivatedGjcSubskillToolNames = customTools
|
|
4077
|
+
.filter(tool => !tool.hidden && !previousGjcSubskillToolNames.has(tool.name))
|
|
4078
|
+
.map(tool => tool.name);
|
|
4079
|
+
await this.#applyActiveToolsByName(
|
|
4080
|
+
Array.from(
|
|
4081
|
+
new Set([
|
|
4082
|
+
...activeNonGjcSubskillToolNames,
|
|
4083
|
+
...preservedGjcSubskillToolNames,
|
|
4084
|
+
...autoActivatedGjcSubskillToolNames,
|
|
4085
|
+
]),
|
|
4086
|
+
),
|
|
4087
|
+
);
|
|
4088
|
+
}
|
|
4089
|
+
|
|
3945
4090
|
/** Whether auto-compaction is currently running */
|
|
3946
4091
|
get isCompacting(): boolean {
|
|
3947
4092
|
return this.#autoCompactionAbortController !== undefined || this.#compactionAbortController !== undefined;
|
|
@@ -4088,6 +4233,45 @@ export class AgentSession {
|
|
|
4088
4233
|
this.#goalModeState = state;
|
|
4089
4234
|
}
|
|
4090
4235
|
|
|
4236
|
+
getWorkflowGateEmitter(): WorkflowGateEmitter | undefined {
|
|
4237
|
+
return this.#workflowGateEmitter;
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
setWorkflowGateEmitter(emitter: WorkflowGateEmitter | undefined): void {
|
|
4241
|
+
this.#workflowGateEmitter = emitter;
|
|
4242
|
+
if (emitter) {
|
|
4243
|
+
this.#ensureWorkflowGateAskTool();
|
|
4244
|
+
}
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4247
|
+
#ensureWorkflowGateAskTool(): void {
|
|
4248
|
+
if (this.#toolRegistry.has("ask")) return;
|
|
4249
|
+
if (!this.#workflowGateToolSession) return;
|
|
4250
|
+
|
|
4251
|
+
const askTool = AskTool.createIf(this.#workflowGateToolSession);
|
|
4252
|
+
if (!askTool) return;
|
|
4253
|
+
|
|
4254
|
+
const wrappedTool = wrapToolWithMetaNotice(askTool as unknown as AgentTool);
|
|
4255
|
+
const finalTool: AgentTool = this.#extensionRunner
|
|
4256
|
+
? new ExtensionToolWrapper(wrappedTool, this.#extensionRunner)
|
|
4257
|
+
: wrappedTool;
|
|
4258
|
+
this.#toolRegistry.set(finalTool.name, finalTool);
|
|
4259
|
+
|
|
4260
|
+
if (!this.getActiveToolNames().includes(finalTool.name)) {
|
|
4261
|
+
const activeTools = [
|
|
4262
|
+
...this.agent.state.tools,
|
|
4263
|
+
this.#wrapToolForDeepInterviewMutationGuard(this.#wrapToolForAcpPermission(finalTool)),
|
|
4264
|
+
];
|
|
4265
|
+
this.agent.setTools(activeTools);
|
|
4266
|
+
this.#invalidateDiscoveryCaches();
|
|
4267
|
+
void this.refreshBaseSystemPrompt().catch(error => {
|
|
4268
|
+
logger.warn("Failed to refresh system prompt after workflow gate ask tool registration", {
|
|
4269
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4270
|
+
});
|
|
4271
|
+
});
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4091
4275
|
get goalRuntime(): GoalRuntime {
|
|
4092
4276
|
return this.#goalRuntime;
|
|
4093
4277
|
}
|
|
@@ -4364,6 +4548,7 @@ export class AgentSession {
|
|
|
4364
4548
|
const message = options?.synthetic
|
|
4365
4549
|
? { role: "developer" as const, content: userContent, attribution: promptAttribution, timestamp: Date.now() }
|
|
4366
4550
|
: { role: "user" as const, content: userContent, attribution: promptAttribution, timestamp: Date.now() };
|
|
4551
|
+
await this.refreshGjcSubskillTools();
|
|
4367
4552
|
|
|
4368
4553
|
if (eagerTodoPrelude) {
|
|
4369
4554
|
this.#toolChoiceQueue.pushOnce(eagerTodoPrelude.toolChoice, {
|
|
@@ -4409,9 +4594,33 @@ export class AgentSession {
|
|
|
4409
4594
|
// of relying on the skill prompt to run its own state-init steps.
|
|
4410
4595
|
if (active) {
|
|
4411
4596
|
await ensureWorkflowSkillActivationState({ cwd: this.sessionManager.getCwd(), skill, sessionId });
|
|
4597
|
+
const subskillDetails = details as {
|
|
4598
|
+
subskillActivation?: LoadedSubskillActivation;
|
|
4599
|
+
subskillActivationSet?: LoadedSubskillActivation[];
|
|
4600
|
+
};
|
|
4601
|
+
const subskillActivations =
|
|
4602
|
+
subskillDetails.subskillActivationSet && subskillDetails.subskillActivationSet.length > 0
|
|
4603
|
+
? subskillDetails.subskillActivationSet
|
|
4604
|
+
: subskillDetails.subskillActivation
|
|
4605
|
+
? [subskillDetails.subskillActivation]
|
|
4606
|
+
: [];
|
|
4607
|
+
if (subskillActivations.length > 0) {
|
|
4608
|
+
const skillBoundActivation = subskillDetails.subskillActivation ?? subskillActivations[0];
|
|
4609
|
+
await syncSkillActiveState({
|
|
4610
|
+
cwd: this.sessionManager.getCwd(),
|
|
4611
|
+
skill,
|
|
4612
|
+
active: true,
|
|
4613
|
+
phase: skillBoundActivation?.phase,
|
|
4614
|
+
sessionId,
|
|
4615
|
+
active_subskills: subskillActivations.map(toActiveSubskillEntry),
|
|
4616
|
+
});
|
|
4617
|
+
}
|
|
4412
4618
|
}
|
|
4413
4619
|
// In-memory tracking keeps `getActiveSkillState` accurate for the chain guard.
|
|
4414
4620
|
this.#activeSkillState = active ? { skill, sessionId } : undefined;
|
|
4621
|
+
if (active) {
|
|
4622
|
+
await this.refreshGjcSubskillTools();
|
|
4623
|
+
}
|
|
4415
4624
|
}
|
|
4416
4625
|
|
|
4417
4626
|
async #syncSkillPromptActiveStateSafely(
|
|
@@ -73,6 +73,17 @@ export class BlobStore {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/** Synchronously read blob by hash, returns Buffer or null if not found. */
|
|
77
|
+
getSync(hash: string): Buffer | null {
|
|
78
|
+
const blobPath = path.join(this.dir, hash);
|
|
79
|
+
try {
|
|
80
|
+
return fs.readFileSync(blobPath);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (isEnoent(err)) return null;
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
/** Check if a blob exists. */
|
|
77
88
|
async has(hash: string): Promise<boolean> {
|
|
78
89
|
try {
|
|
@@ -84,6 +95,43 @@ export class BlobStore {
|
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
97
|
|
|
98
|
+
export class MemoryBlobStore extends BlobStore {
|
|
99
|
+
#blobs = new Map<string, Buffer>();
|
|
100
|
+
|
|
101
|
+
constructor() {
|
|
102
|
+
super(":memory:");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async put(data: Buffer): Promise<BlobPutResult> {
|
|
106
|
+
return this.putSync(data);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
putSync(data: Buffer): BlobPutResult {
|
|
110
|
+
const hash = new Bun.SHA256().update(data).digest("hex");
|
|
111
|
+
this.#blobs.set(hash, Buffer.from(data));
|
|
112
|
+
return {
|
|
113
|
+
hash,
|
|
114
|
+
path: `memory:${hash}`,
|
|
115
|
+
get ref() {
|
|
116
|
+
return `${BLOB_PREFIX}${hash}`;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async get(hash: string): Promise<Buffer | null> {
|
|
122
|
+
return this.getSync(hash);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
getSync(hash: string): Buffer | null {
|
|
126
|
+
const data = this.#blobs.get(hash);
|
|
127
|
+
return data ? Buffer.from(data) : null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async has(hash: string): Promise<boolean> {
|
|
131
|
+
return this.#blobs.has(hash);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
87
135
|
/** Check if a data string is a blob reference. */
|
|
88
136
|
export function isBlobRef(data: string): boolean {
|
|
89
137
|
return data.startsWith(BLOB_PREFIX);
|
|
@@ -166,3 +214,39 @@ export async function resolveImageData(blobStore: BlobStore, data: string): Prom
|
|
|
166
214
|
}
|
|
167
215
|
return buffer.toString("base64");
|
|
168
216
|
}
|
|
217
|
+
|
|
218
|
+
/** Synchronously resolve an externalized provider image data URL back to its original string. */
|
|
219
|
+
export function resolveImageDataUrlSync(blobStore: BlobStore, data: string): string {
|
|
220
|
+
const hash = parseBlobRef(data);
|
|
221
|
+
if (!hash) return data;
|
|
222
|
+
const buffer = blobStore.getSync(hash);
|
|
223
|
+
if (!buffer) {
|
|
224
|
+
logger.warn("Blob not found for persisted image data URL", { hash });
|
|
225
|
+
return data;
|
|
226
|
+
}
|
|
227
|
+
return buffer.toString("utf8");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Synchronously resolve a blob reference back to base64 data. */
|
|
231
|
+
export function resolveImageDataSync(blobStore: BlobStore, data: string): string {
|
|
232
|
+
const hash = parseBlobRef(data);
|
|
233
|
+
if (!hash) return data;
|
|
234
|
+
const buffer = blobStore.getSync(hash);
|
|
235
|
+
if (!buffer) {
|
|
236
|
+
logger.warn("Blob not found for image reference", { hash });
|
|
237
|
+
return data;
|
|
238
|
+
}
|
|
239
|
+
return buffer.toString("base64");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Synchronously resolve a blob reference back to utf8 text. */
|
|
243
|
+
export function resolveTextBlobSync(blobStore: BlobStore, data: string): string {
|
|
244
|
+
const hash = parseBlobRef(data);
|
|
245
|
+
if (!hash) return data;
|
|
246
|
+
const buffer = blobStore.getSync(hash);
|
|
247
|
+
if (!buffer) {
|
|
248
|
+
logger.warn("Blob not found for text reference", { hash });
|
|
249
|
+
return data;
|
|
250
|
+
}
|
|
251
|
+
return buffer.toString("utf8");
|
|
252
|
+
}
|
package/src/session/messages.ts
CHANGED
|
@@ -27,6 +27,7 @@ export {
|
|
|
27
27
|
createCompactionSummaryMessage,
|
|
28
28
|
} from "@gajae-code/agent-core/compaction/messages";
|
|
29
29
|
|
|
30
|
+
import type { LoadedSubskillActivation } from "../extensibility/gjc-plugins";
|
|
30
31
|
import type { OutputMeta } from "../tools/output-meta";
|
|
31
32
|
import { formatOutputNotice } from "../tools/output-meta";
|
|
32
33
|
|
|
@@ -37,6 +38,8 @@ export interface SkillPromptDetails {
|
|
|
37
38
|
path: string;
|
|
38
39
|
args?: string;
|
|
39
40
|
lineCount: number;
|
|
41
|
+
subskillActivation?: LoadedSubskillActivation;
|
|
42
|
+
subskillActivationSet?: LoadedSubskillActivation[];
|
|
40
43
|
/** Internal: tag used by AgentSession to remove the pending-display chip
|
|
41
44
|
* from `#steeringMessages` / `#followUpMessages` when the agent consumes
|
|
42
45
|
* this message. Not surfaced to renderers; the `__` prefix signals
|