@gajae-code/coding-agent 0.16.3 → 0.16.6
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 +113 -0
- package/dist/types/capability/types.d.ts +4 -0
- package/dist/types/cli/args.d.ts +2 -2
- package/dist/types/cli/customize-doctor.d.ts +22 -0
- package/dist/types/cli/root-flags.d.ts +4 -2
- package/dist/types/cli.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +1 -1
- package/dist/types/config/autorouting-tier-map.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +31 -3
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +9 -0
- package/dist/types/config/settings-schema.d.ts +29 -1
- package/dist/types/coordinator-mcp/question-state.d.ts +7 -0
- package/dist/types/coordinator-mcp/server.d.ts +7 -0
- package/dist/types/discovery/claude-plugins.d.ts +3 -1
- package/dist/types/discovery/helpers.d.ts +35 -0
- package/dist/types/exec/bash-executor.d.ts +17 -1
- package/dist/types/exec/bash-shell-guardian.d.ts +15 -0
- package/dist/types/exec/bash-shell-runtime-entry.d.ts +2 -0
- package/dist/types/exec/bash-shell-signals.d.ts +2 -0
- package/dist/types/exec/bash-shell-supervisor-entry.d.ts +1 -0
- package/dist/types/exec/bash-shell-supervisor.d.ts +10 -0
- package/dist/types/exec/bash-shell-worker-entry.d.ts +2 -0
- package/dist/types/exec/bash-shell-worker-protocol.d.ts +63 -0
- package/dist/types/exec/bash-shell-worker.d.ts +1 -0
- package/dist/types/exec/isolated-shell.d.ts +19 -0
- package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +9 -0
- package/dist/types/extensibility/extensions/function-hooks.d.ts +169 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/runner.d.ts +46 -6
- package/dist/types/extensibility/extensions/types.d.ts +16 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/constrained-hooks.d.ts +35 -2
- package/dist/types/extensibility/gjc-plugins/mcp-policy.d.ts +16 -0
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -0
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/hooks/types.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +5 -2
- package/dist/types/extensibility/shared-events.d.ts +1 -1
- package/dist/types/extensibility/skill-management.d.ts +9 -4
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/empty-delete-gc.d.ts +4 -1
- package/dist/types/gjc-runtime/linux-proc.d.ts +2 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +14 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +41 -3
- package/dist/types/gjc-runtime/ultragoal-succession.d.ts +251 -0
- package/dist/types/modes/components/assistant-message.d.ts +1 -2
- package/dist/types/modes/components/bash-execution.d.ts +1 -0
- package/dist/types/modes/components/execution-shared.d.ts +1 -0
- package/dist/types/modes/components/settings-selector.d.ts +6 -1
- package/dist/types/modes/components/status-line/command.d.ts +35 -0
- package/dist/types/modes/components/status-line/index.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +5 -0
- package/dist/types/modes/components/tool-status-header.d.ts +14 -0
- package/dist/types/modes/controllers/event-controller.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/types.d.ts +7 -0
- package/dist/types/runtime-mcp/client.d.ts +9 -1
- package/dist/types/runtime-mcp/manager.d.ts +7 -1
- package/dist/types/runtime-mcp/pool.d.ts +22 -3
- package/dist/types/runtime-mcp/transports/stdio.d.ts +0 -4
- package/dist/types/runtime-mcp/types.d.ts +22 -0
- package/dist/types/sdk/broker/ensure.d.ts +32 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +0 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
- package/dist/types/sdk/broker/startup-failure.d.ts +4 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +2 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +12 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +17 -2
- package/dist/types/sdk/bus/conversation-store.d.ts +11 -0
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +8 -8
- package/dist/types/sdk/bus/slack-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/slack-live-provider.d.ts +6 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +12 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +8 -0
- package/dist/types/sdk/client/client.d.ts +6 -0
- package/dist/types/sdk/host/host.d.ts +3 -1
- package/dist/types/sdk/host/session-runtime.d.ts +26 -1
- package/dist/types/sdk/lifecycle/service.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +10 -2
- package/dist/types/sdk/session-api-key.d.ts +26 -0
- package/dist/types/sdk/session.d.ts +5 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +11 -0
- package/dist/types/session/fallback-chain-controller.d.ts +15 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/setup/paseo/announce.d.ts +112 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +2 -1
- package/dist/types/skill-state/canonical-skills.d.ts +4 -0
- package/dist/types/system-prompt.d.ts +10 -0
- package/dist/types/task/executor.d.ts +5 -1
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/fetch.d.ts +7 -0
- package/dist/types/tools/github-cache.d.ts +2 -1
- package/dist/types/tools/index.d.ts +10 -0
- package/dist/types/tools/path-utils.d.ts +2 -0
- package/dist/types/tools/search.d.ts +6 -0
- package/package.json +9 -7
- package/scripts/capture-status-line-custom-editor-showcase.ts +151 -0
- package/scripts/generate-sdk-operation-inventory.ts +11 -0
- package/scripts/verify-status-line-custom-editor-showcase.ts +309 -0
- package/src/capability/index.ts +14 -2
- package/src/capability/types.ts +4 -0
- package/src/cli/args.ts +20 -9
- package/src/cli/customize-doctor.ts +155 -12
- package/src/cli/root-flags.ts +5 -3
- package/src/cli.ts +22 -0
- package/src/commands/sdk.ts +74 -31
- package/src/config/autorouting-tier-map.ts +1 -0
- package/src/config/file-lock-gc.ts +40 -2
- package/src/config/file-lock.ts +379 -31
- package/src/config/model-preset-registry.ts +120 -19
- package/src/config/model-profiles.ts +40 -0
- package/src/config/model-registry.ts +73 -23
- package/src/config/model-resolver.ts +48 -0
- package/src/config/settings-schema.ts +33 -1
- package/src/config/settings.ts +1 -0
- package/src/coordinator-mcp/question-state.ts +33 -2
- package/src/coordinator-mcp/server.ts +477 -101
- package/src/crash/sanitize.ts +1 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +11 -11
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +13 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +22 -0
- package/src/discovery/builtin.ts +52 -55
- package/src/discovery/claude-plugins.ts +12 -4
- package/src/discovery/helpers.ts +307 -34
- package/src/exec/bash-executor.ts +330 -50
- package/src/exec/bash-shell-guardian.ts +388 -0
- package/src/exec/bash-shell-runtime-entry.ts +5 -0
- package/src/exec/bash-shell-signals.ts +29 -0
- package/src/exec/bash-shell-supervisor-entry.ts +3 -0
- package/src/exec/bash-shell-supervisor.ts +359 -0
- package/src/exec/bash-shell-worker-entry.ts +5 -0
- package/src/exec/bash-shell-worker-protocol.ts +36 -0
- package/src/exec/bash-shell-worker.ts +116 -0
- package/src/exec/isolated-shell.ts +393 -0
- package/src/extensibility/extensions/function-hooks-internal.ts +73 -0
- package/src/extensibility/extensions/function-hooks.ts +959 -0
- package/src/extensibility/extensions/index.ts +22 -0
- package/src/extensibility/extensions/loader.ts +53 -2
- package/src/extensibility/extensions/runner.ts +895 -264
- package/src/extensibility/extensions/types.ts +42 -0
- package/src/extensibility/extensions/wrapper.ts +56 -15
- package/src/extensibility/gjc-plugins/compiler.ts +228 -60
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +321 -23
- package/src/extensibility/gjc-plugins/installer.ts +13 -12
- package/src/extensibility/gjc-plugins/mcp-policy.ts +81 -52
- package/src/extensibility/gjc-plugins/paths.ts +13 -0
- package/src/extensibility/gjc-plugins/registry.ts +113 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +758 -16
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +20 -2
- package/src/extensibility/gjc-plugins/schema.ts +121 -4
- package/src/extensibility/gjc-plugins/types.ts +25 -0
- package/src/extensibility/hooks/loader.ts +133 -16
- package/src/extensibility/hooks/types.ts +28 -0
- package/src/extensibility/runtime-skill-discovery.ts +149 -190
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/skill-management.ts +200 -52
- package/src/extensibility/skills.ts +73 -25
- package/src/gjc-runtime/empty-delete-gc.ts +94 -4
- package/src/gjc-runtime/gc-runtime.ts +29 -0
- package/src/gjc-runtime/linux-proc.ts +14 -0
- package/src/gjc-runtime/repository-binding.ts +1 -1
- package/src/gjc-runtime/session-state-lock.ts +143 -10
- package/src/gjc-runtime/session-state-sidecar.ts +27 -11
- package/src/gjc-runtime/state-writer.ts +30 -29
- package/src/gjc-runtime/ultragoal-runtime.ts +189 -47
- package/src/gjc-runtime/ultragoal-succession.ts +1667 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +52 -1
- package/src/gjc-runtime/workflow-manifest.ts +16 -0
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +12 -12
- package/src/lsp/config.ts +10 -3
- package/src/lsp/index.ts +1 -1
- package/src/lsp/path-trust.ts +69 -14
- package/src/main.ts +78 -35
- package/src/modes/DESIGN.md +54 -0
- package/src/modes/acp/acp-agent.ts +16 -3
- package/src/modes/components/assistant-message.ts +22 -9
- package/src/modes/components/bash-execution.ts +4 -1
- package/src/modes/components/execution-shared.ts +4 -1
- package/src/modes/components/model-selector.ts +166 -33
- package/src/modes/components/session-observer-overlay.ts +1 -1
- package/src/modes/components/settings-selector.ts +1075 -235
- package/src/modes/components/status-line/command.ts +190 -0
- package/src/modes/components/status-line/index.ts +1 -0
- package/src/modes/components/status-line/segments.ts +32 -5
- package/src/modes/components/status-line/types.ts +5 -0
- package/src/modes/components/tool-status-header.ts +396 -22
- package/src/modes/controllers/command-controller.ts +3 -0
- package/src/modes/controllers/event-controller.ts +151 -7
- package/src/modes/controllers/extension-ui-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +6 -3
- package/src/modes/controllers/selector-controller.ts +21 -0
- package/src/modes/interactive-mode.ts +53 -6
- package/src/modes/print-mode.ts +5 -1
- package/src/modes/prompt-action-autocomplete.ts +54 -27
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/types.ts +17 -3
- package/src/modes/utils/ui-helpers.ts +2 -0
- package/src/prompts/system/system-prompt.md +8 -0
- package/src/prompts/tools/search.md +2 -0
- package/src/prompts/tools/subagent.md +1 -0
- package/src/runtime-mcp/client.ts +60 -17
- package/src/runtime-mcp/manager.ts +189 -14
- package/src/runtime-mcp/pool.test.ts +218 -0
- package/src/runtime-mcp/pool.ts +224 -23
- package/src/runtime-mcp/transports/stdio.ts +158 -24
- package/src/runtime-mcp/types.ts +24 -0
- package/src/sdk/broker/broker.ts +124 -32
- package/src/sdk/broker/ensure.ts +248 -41
- package/src/sdk/broker/lifecycle-ledger.ts +7 -17
- package/src/sdk/broker/lifecycle.ts +56 -6
- package/src/sdk/broker/startup-failure.ts +15 -6
- package/src/sdk/bus/chat-daemon-control.ts +3 -1
- package/src/sdk/bus/chat-daemon-runtime.ts +72 -6
- package/src/sdk/bus/chat-effect-journal.ts +132 -7
- package/src/sdk/bus/conversation-store.ts +29 -0
- package/src/sdk/bus/lifecycle-commands.ts +17 -11
- package/src/sdk/bus/slack-conversation.ts +1 -0
- package/src/sdk/bus/slack-daemon.ts +478 -49
- package/src/sdk/bus/slack-live-provider.ts +12 -0
- package/src/sdk/bus/slack-provider.ts +5 -0
- package/src/sdk/bus/telegram-daemon.ts +16 -2
- package/src/sdk/bus/topic-registry.ts +19 -0
- package/src/sdk/cli/master-cli.ts +1 -1
- package/src/sdk/cli/session-cli.ts +11 -8
- package/src/sdk/client/client.ts +66 -17
- package/src/sdk/host/host.ts +29 -9
- package/src/sdk/host/query/revision-store.ts +19 -13
- package/src/sdk/host/reverse-leases.ts +7 -4
- package/src/sdk/host/session-runtime.test.ts +52 -10
- package/src/sdk/host/session-runtime.ts +383 -44
- package/src/sdk/lifecycle/service.ts +4 -0
- package/src/sdk/protocol/operation-inventory.generated.json +77 -0
- package/src/sdk/router/session-router.ts +89 -38
- package/src/sdk/session-api-key.ts +94 -0
- package/src/sdk/session.ts +228 -55
- package/src/sdk/transport/relay.ts +35 -13
- package/src/sdk/transport/serve-cli.ts +3 -3
- package/src/session/agent-session.ts +240 -90
- package/src/session/contribution-prep.ts +214 -21
- package/src/session/fallback-chain-controller.ts +38 -0
- package/src/session/internal/managed-session-storage.ts +19 -5
- package/src/session/messages.ts +5 -0
- package/src/session/session-manager.ts +29 -5
- package/src/session-import/redact.ts +5 -1
- package/src/setup/paseo/announce.ts +456 -0
- package/src/setup/paseo/setup-deps.ts +15 -3
- package/src/skill-state/canonical-skills.ts +12 -0
- package/src/skills/skills.test.ts +41 -21
- package/src/slash-commands/builtin-registry.ts +1 -0
- package/src/system-prompt.ts +29 -3
- package/src/task/executor.ts +7 -1
- package/src/task/index.ts +21 -4
- package/src/tools/bash.ts +63 -19
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +29 -1
- package/src/tools/gh.ts +26 -3
- package/src/tools/github-cache.ts +68 -16
- package/src/tools/index.ts +10 -0
- package/src/tools/job.ts +21 -4
- package/src/tools/monitor.ts +8 -2
- package/src/tools/path-utils.ts +7 -0
- package/src/tools/read.ts +14 -2
- package/src/tools/render-utils.ts +1 -3
- package/src/tools/resource-gc.ts +28 -8
- package/src/tools/search.ts +116 -58
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +37 -2
- package/src/tools/subagent.ts +6 -3
- package/src/tools/tool-catalog.generated.ts +10 -3
- package/src/tools/ultragoal-ask-guard.ts +2 -2
- package/src/web/insane/bridge.ts +113 -23
- package/src/web/search/providers/perplexity.ts +102 -41
package/src/sdk/session.ts
CHANGED
|
@@ -32,8 +32,10 @@ import {
|
|
|
32
32
|
$flag,
|
|
33
33
|
getAgentDbPath,
|
|
34
34
|
getAgentDir,
|
|
35
|
+
getAgentProfileAuthority,
|
|
35
36
|
getProjectDir,
|
|
36
37
|
logger,
|
|
38
|
+
normalizePathForComparison,
|
|
37
39
|
postmortem,
|
|
38
40
|
prompt,
|
|
39
41
|
Snowflake,
|
|
@@ -91,10 +93,14 @@ import { CustomToolAdapter } from "../extensibility/custom-tools/wrapper";
|
|
|
91
93
|
import {
|
|
92
94
|
createCustomToolSettings,
|
|
93
95
|
type ExtensionContext,
|
|
96
|
+
type ExtensionEvent,
|
|
94
97
|
type ExtensionFactory,
|
|
95
98
|
ExtensionRunner,
|
|
96
99
|
ExtensionToolWrapper,
|
|
97
100
|
type ExtensionUIContext,
|
|
101
|
+
type FunctionHook,
|
|
102
|
+
type FunctionHookEventType,
|
|
103
|
+
type FunctionHookResult,
|
|
98
104
|
type LoadExtensionsResult,
|
|
99
105
|
loadExtensionFromFactory,
|
|
100
106
|
type ToolDefinition,
|
|
@@ -168,6 +174,7 @@ import {
|
|
|
168
174
|
unregisterOwnedRegistration,
|
|
169
175
|
} from "../session/terminal-abort";
|
|
170
176
|
import { formatNoModelsAvailableFallback } from "../setup/model-onboarding-guidance";
|
|
177
|
+
import { getSkillFilesystemIdentity } from "../skill-state/canonical-skills";
|
|
171
178
|
import {
|
|
172
179
|
type BuildSystemPromptResult,
|
|
173
180
|
buildSystemPrompt as buildSystemPromptInternal,
|
|
@@ -197,6 +204,11 @@ import { EventBus } from "../utils/event-bus";
|
|
|
197
204
|
import { buildNamedToolChoice, buildNamedToolChoiceResult } from "../utils/tool-choice";
|
|
198
205
|
import type { WorkspaceTree } from "../workspace-tree";
|
|
199
206
|
import { createSessionLifecycleService } from "./lifecycle/client";
|
|
207
|
+
import {
|
|
208
|
+
isStableSessionApiKeyCredentialType,
|
|
209
|
+
lookupSessionApiKey,
|
|
210
|
+
resolveLiveSessionApiKeyModel,
|
|
211
|
+
} from "./session-api-key";
|
|
200
212
|
import {
|
|
201
213
|
attachLifecycleStartupCapability,
|
|
202
214
|
lifecycleMcpStartupTimeoutOption,
|
|
@@ -433,6 +445,8 @@ export interface CreateAgentSessionOptions {
|
|
|
433
445
|
cwd?: string;
|
|
434
446
|
/** Global config directory. Default: ~/.gjc/agent */
|
|
435
447
|
agentDir?: string;
|
|
448
|
+
/** Resolver-owned classification for `agentDir`; required when authority must survive HOME/config refreshes. */
|
|
449
|
+
profileAuthority?: "default" | "custom";
|
|
436
450
|
/** Spawns to allow. Default: "*" */
|
|
437
451
|
spawns?: string;
|
|
438
452
|
|
|
@@ -776,10 +790,11 @@ export async function discoverSkills(
|
|
|
776
790
|
*/
|
|
777
791
|
export async function discoverContextFiles(
|
|
778
792
|
cwd?: string,
|
|
779
|
-
|
|
793
|
+
agentDir?: string,
|
|
780
794
|
): Promise<Array<{ path: string; content: string; depth?: number }>> {
|
|
781
795
|
return await loadContextFilesInternal({
|
|
782
796
|
cwd: cwd ?? getProjectDir(),
|
|
797
|
+
agentDir,
|
|
783
798
|
});
|
|
784
799
|
}
|
|
785
800
|
|
|
@@ -816,6 +831,8 @@ export interface BuildSystemPromptOptions {
|
|
|
816
831
|
skills?: Skill[];
|
|
817
832
|
contextFiles?: Array<{ path: string; content: string }>;
|
|
818
833
|
cwd?: string;
|
|
834
|
+
agentDir?: string;
|
|
835
|
+
profileAuthority?: "default" | "custom";
|
|
819
836
|
appendPrompt?: string;
|
|
820
837
|
repeatToolDescriptions?: boolean;
|
|
821
838
|
}
|
|
@@ -829,6 +846,8 @@ export interface BuildSystemPromptOptions {
|
|
|
829
846
|
export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}): Promise<BuildSystemPromptResult> {
|
|
830
847
|
return await buildSystemPromptInternal({
|
|
831
848
|
cwd: options.cwd,
|
|
849
|
+
agentDir: options.agentDir,
|
|
850
|
+
profileAuthority: options.profileAuthority,
|
|
832
851
|
skills: options.skills,
|
|
833
852
|
contextFiles: options.contextFiles,
|
|
834
853
|
appendSystemPrompt: options.appendPrompt,
|
|
@@ -1010,14 +1029,89 @@ export function createPluginHooksExtension(hooks: ConstrainedPluginHook[]): Exte
|
|
|
1010
1029
|
if (!normalized) throw new Error("Hook normalization invariant violated");
|
|
1011
1030
|
const registrationEvent = normalized.runtimeEvent;
|
|
1012
1031
|
const target = normalized.toolName === "*" ? undefined : normalized.toolName;
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1032
|
+
if (!hook.functionHook) {
|
|
1033
|
+
const legacyHandler: (...args: unknown[]) => unknown = target
|
|
1034
|
+
? (event: unknown, ...rest: unknown[]) => {
|
|
1035
|
+
const record = event as { toolName?: string; tool?: { name?: string }; name?: string } | undefined;
|
|
1036
|
+
const toolName = record?.toolName ?? record?.tool?.name ?? record?.name;
|
|
1037
|
+
if (toolName !== target) return undefined;
|
|
1038
|
+
return (hook.handler as (...args: unknown[]) => unknown)(event, ...rest);
|
|
1039
|
+
}
|
|
1040
|
+
: (hook.handler as (...args: unknown[]) => unknown);
|
|
1041
|
+
(api.on as (event: string, handler: (...args: unknown[]) => void) => void)(
|
|
1042
|
+
registrationEvent,
|
|
1043
|
+
legacyHandler,
|
|
1044
|
+
);
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
const handler: FunctionHook = async (invocation, _capabilities, next) => {
|
|
1048
|
+
const legacyResult = await (hook.handler as (...args: unknown[]) => unknown)(invocation.payload, undefined);
|
|
1049
|
+
if (legacyResult === undefined) return await next();
|
|
1050
|
+
if (invocation.eventType === "tool_call") {
|
|
1051
|
+
const result = legacyResult as { block?: unknown; reason?: unknown; input?: unknown };
|
|
1052
|
+
if (result.block === true) {
|
|
1053
|
+
return {
|
|
1054
|
+
action: "deny",
|
|
1055
|
+
reason:
|
|
1056
|
+
typeof result.reason === "string" ? result.reason : "Tool execution blocked by plugin hook",
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
if (result.input !== undefined) {
|
|
1060
|
+
return {
|
|
1061
|
+
action: "continue",
|
|
1062
|
+
event: { ...invocation.payload, input: result.input as Record<string, unknown> } as ExtensionEvent,
|
|
1063
|
+
} as FunctionHookResult;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (invocation.eventType === "tool_result") {
|
|
1067
|
+
const result = legacyResult as { content?: unknown; details?: unknown; isError?: unknown };
|
|
1068
|
+
if (result.content !== undefined || result.details !== undefined || result.isError !== undefined) {
|
|
1069
|
+
return {
|
|
1070
|
+
action: "continue",
|
|
1071
|
+
event: {
|
|
1072
|
+
...invocation.payload,
|
|
1073
|
+
...(result.content === undefined ? {} : { content: result.content }),
|
|
1074
|
+
...(result.details === undefined ? {} : { details: result.details }),
|
|
1075
|
+
...(result.isError === undefined ? {} : { isError: result.isError }),
|
|
1076
|
+
},
|
|
1077
|
+
} as FunctionHookResult;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (invocation.eventType === "context" && (legacyResult as { messages?: unknown }).messages !== undefined) {
|
|
1081
|
+
return {
|
|
1082
|
+
action: "continue",
|
|
1083
|
+
event: {
|
|
1084
|
+
...invocation.payload,
|
|
1085
|
+
messages: (legacyResult as { messages: unknown }).messages,
|
|
1086
|
+
} as ExtensionEvent,
|
|
1087
|
+
} as FunctionHookResult;
|
|
1088
|
+
}
|
|
1089
|
+
if (
|
|
1090
|
+
invocation.eventType.startsWith("session_before_") &&
|
|
1091
|
+
(legacyResult as { cancel?: unknown }).cancel === true
|
|
1092
|
+
) {
|
|
1093
|
+
return { action: "deny", reason: "Session change blocked by plugin hook" };
|
|
1094
|
+
}
|
|
1095
|
+
if (invocation.eventType === "before_agent_start") {
|
|
1096
|
+
const result = legacyResult as { message?: unknown; systemPrompt?: unknown };
|
|
1097
|
+
if (result.message !== undefined || result.systemPrompt !== undefined) {
|
|
1098
|
+
return {
|
|
1099
|
+
action: "return",
|
|
1100
|
+
value: {
|
|
1101
|
+
...(result.message === undefined ? {} : { messages: [result.message] }),
|
|
1102
|
+
...(result.systemPrompt === undefined ? {} : { systemPrompt: result.systemPrompt }),
|
|
1103
|
+
},
|
|
1104
|
+
} as FunctionHookResult;
|
|
1018
1105
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1106
|
+
}
|
|
1107
|
+
return await next();
|
|
1108
|
+
};
|
|
1109
|
+
const options = {
|
|
1110
|
+
...(target === undefined ? {} : { target }),
|
|
1111
|
+
registrationId: hook.extensionId,
|
|
1112
|
+
...(hook.grant ?? {}),
|
|
1113
|
+
};
|
|
1114
|
+
api.registerFunctionHook(registrationEvent as FunctionHookEventType, handler, options);
|
|
1021
1115
|
}
|
|
1022
1116
|
};
|
|
1023
1117
|
}
|
|
@@ -1107,14 +1201,14 @@ function buildMCPPromptCommands(manager: MCPManager): LoadedCustomCommand[] {
|
|
|
1107
1201
|
function withEmbeddedDefaultGjcSkills(skills: Skill[]): Skill[] {
|
|
1108
1202
|
const byName = new Map<string, Skill>();
|
|
1109
1203
|
for (const skill of skills) {
|
|
1110
|
-
const key = skill.name
|
|
1204
|
+
const key = getSkillFilesystemIdentity(skill.name);
|
|
1111
1205
|
if (!byName.has(key)) byName.set(key, skill);
|
|
1112
1206
|
}
|
|
1113
1207
|
// The four public GJC workflow skills are a product invariant: even if a
|
|
1114
1208
|
// caller-supplied or filesystem skill shares a name, the bundled definition
|
|
1115
1209
|
// wins so workflow routing can never be silently hijacked.
|
|
1116
1210
|
for (const defaultSkill of getEmbeddedDefaultGjcSkills()) {
|
|
1117
|
-
byName.set(defaultSkill.name
|
|
1211
|
+
byName.set(getSkillFilesystemIdentity(defaultSkill.name), defaultSkill);
|
|
1118
1212
|
}
|
|
1119
1213
|
return [...byName.values()];
|
|
1120
1214
|
}
|
|
@@ -1388,7 +1482,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1388
1482
|
}
|
|
1389
1483
|
const cwd = options.cwd ?? getProjectDir();
|
|
1390
1484
|
const explicitMcpConfigPath = !isCanonicalSubSession && !options.mcpManager ? options.mcpConfigPath : undefined;
|
|
1391
|
-
const agentDir = options.agentDir ?? getDefaultAgentDir();
|
|
1485
|
+
const agentDir = options.agentDir ?? options.settings?.getAgentDir() ?? getDefaultAgentDir();
|
|
1486
|
+
const profileAuthority =
|
|
1487
|
+
options.profileAuthority ??
|
|
1488
|
+
(options.agentDir !== undefined || options.settings !== undefined
|
|
1489
|
+
? normalizePathForComparison(agentDir) !== normalizePathForComparison(getAgentDir())
|
|
1490
|
+
? "custom"
|
|
1491
|
+
: getAgentProfileAuthority()
|
|
1492
|
+
: getAgentProfileAuthority());
|
|
1392
1493
|
const eventBus = options.eventBus ?? new EventBus();
|
|
1393
1494
|
const hasInjectedAuth = options.authStorage !== undefined || options.modelRegistry !== undefined;
|
|
1394
1495
|
|
|
@@ -1576,7 +1677,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1576
1677
|
// session-context build, tool creation, MCP discovery, and extension discovery.
|
|
1577
1678
|
const contextFilesResultPromise = options.contextFiles
|
|
1578
1679
|
? Promise.resolve({ contextFiles: options.contextFiles, warnings: [] })
|
|
1579
|
-
: logger.time("discoverContextFiles", loadContextFilesResultInternal, { cwd });
|
|
1680
|
+
: logger.time("discoverContextFiles", loadContextFilesResultInternal, { cwd, agentDir, profileAuthority });
|
|
1580
1681
|
contextFilesResultPromise.catch(() => {});
|
|
1581
1682
|
const promptTemplatesPromise = options.promptTemplates
|
|
1582
1683
|
? Promise.resolve(options.promptTemplates)
|
|
@@ -1977,9 +2078,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1977
2078
|
skills = withEmbeddedDefaultGjcSkills(options.skills);
|
|
1978
2079
|
skillWarnings = [];
|
|
1979
2080
|
} else if (settings.get("skills.enabled")) {
|
|
1980
|
-
const skillsResult = await logger.time("
|
|
2081
|
+
const skillsResult = await logger.time("discoverSkills", loadSkills, {
|
|
1981
2082
|
...settings.getGroup("skills"),
|
|
1982
2083
|
agentDir,
|
|
2084
|
+
profileAuthority,
|
|
1983
2085
|
cwd,
|
|
1984
2086
|
disabledExtensions: settings.get("disabledExtensions"),
|
|
1985
2087
|
});
|
|
@@ -2001,7 +2103,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2001
2103
|
const rulesResult =
|
|
2002
2104
|
options.rules !== undefined
|
|
2003
2105
|
? { items: options.rules, warnings: undefined }
|
|
2004
|
-
: await loadCapability<Rule>(ruleCapability.id, { cwd, agentDir, settings });
|
|
2106
|
+
: await loadCapability<Rule>(ruleCapability.id, { cwd, agentDir, profileAuthority, settings });
|
|
2005
2107
|
const rulebookRules: Rule[] = [];
|
|
2006
2108
|
const alwaysApplyRules: Rule[] = [];
|
|
2007
2109
|
for (const rule of rulesResult.items) {
|
|
@@ -2329,7 +2431,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2329
2431
|
*/
|
|
2330
2432
|
const applyRescopedReadState = async (to: string): Promise<void> => {
|
|
2331
2433
|
try {
|
|
2332
|
-
const rediscovered = await loadContextFilesResultInternal({ cwd: to });
|
|
2434
|
+
const rediscovered = await loadContextFilesResultInternal({ cwd: to, agentDir, profileAuthority });
|
|
2333
2435
|
contextFiles = rediscovered.contextFiles;
|
|
2334
2436
|
} catch (error) {
|
|
2335
2437
|
logger.warn("Failed to re-discover context files after session rescope", {
|
|
@@ -2338,15 +2440,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2338
2440
|
}
|
|
2339
2441
|
if (options.skills === undefined && settings.get("skills.enabled")) {
|
|
2340
2442
|
try {
|
|
2341
|
-
|
|
2342
|
-
...settings.getGroup("skills"),
|
|
2343
|
-
agentDir,
|
|
2344
|
-
cwd: to,
|
|
2345
|
-
disabledExtensions: settings.get("disabledExtensions"),
|
|
2346
|
-
});
|
|
2347
|
-
skills = withEmbeddedDefaultGjcSkills(reloaded.skills);
|
|
2348
|
-
if (!options.parentTaskPrefix) setActiveSkills(skills);
|
|
2349
|
-
await session?.replaceSkills(skills);
|
|
2443
|
+
await session?.reloadSkills(to);
|
|
2350
2444
|
} catch (error) {
|
|
2351
2445
|
logger.warn("Failed to reload skills after session rescope", { error: safeErrorForLog(error) });
|
|
2352
2446
|
}
|
|
@@ -2378,6 +2472,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2378
2472
|
return sessionManager.getCwd();
|
|
2379
2473
|
},
|
|
2380
2474
|
hasUI: options.hasUI ?? false,
|
|
2475
|
+
profileAuthority,
|
|
2381
2476
|
workflowGateEligible: true,
|
|
2382
2477
|
enableLsp,
|
|
2383
2478
|
get hasEditTool() {
|
|
@@ -2696,6 +2791,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2696
2791
|
}
|
|
2697
2792
|
: {}),
|
|
2698
2793
|
getSessionFile: () => sessionManager.getSessionFile() ?? null,
|
|
2794
|
+
getSessionAgentDir: () => session?.getSessionAgentDir() ?? options.agentDir ?? settings.getAgentDir(),
|
|
2699
2795
|
getEvalKernelOwnerId: () => evalKernelOwnerId,
|
|
2700
2796
|
assertEvalExecutionAllowed: () => session?.assertEvalExecutionAllowed(),
|
|
2701
2797
|
trackEvalExecution: (execution, abortController) =>
|
|
@@ -2708,13 +2804,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2708
2804
|
else signal.addEventListener("abort", () => resolve(), { once: true });
|
|
2709
2805
|
return promise;
|
|
2710
2806
|
},
|
|
2807
|
+
getSessionId: () => sessionManager.getSessionId(),
|
|
2711
2808
|
// Subagents inherit the parent's manager; its registered endpoint is
|
|
2712
2809
|
// authoritative for owned-registration keying and endpoint-first
|
|
2713
2810
|
// manager lookup (the child's own id is never registered), so tools
|
|
2714
2811
|
// pass the same endpoint the manager's completion callback resolves
|
|
2715
2812
|
// (review thread P1). For a top-level session this equals the
|
|
2716
2813
|
// session id.
|
|
2717
|
-
|
|
2814
|
+
getAsyncEndpointId: () => AsyncJobManager.endpointIdOf(asyncJobManager) ?? asyncJobEndpointId,
|
|
2718
2815
|
registerForegroundFoldParticipant: adapter =>
|
|
2719
2816
|
session?.registerForegroundFoldParticipant(adapter) ?? (() => {}),
|
|
2720
2817
|
hasForegroundBashBackgroundRequestHandler: () => session?.hasForegroundBashBackgroundRequestHandler() ?? false,
|
|
@@ -2976,7 +3073,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2976
3073
|
cwdCapturingToolNames.push(...pluginToolResult.tools.map(tool => tool.name));
|
|
2977
3074
|
}
|
|
2978
3075
|
for (const q of pluginToolResult.quarantine) {
|
|
2979
|
-
gjcFindings.add({
|
|
3076
|
+
gjcFindings.add({
|
|
3077
|
+
identity: q.identity,
|
|
3078
|
+
surfaceId: q.surfaceId,
|
|
3079
|
+
code: q.code,
|
|
3080
|
+
message: q.message,
|
|
3081
|
+
decision: "quarantined",
|
|
3082
|
+
provenance: { source: "plugin-bundle", plugin: q.plugin },
|
|
3083
|
+
});
|
|
2980
3084
|
logger.warn("Quarantined GJC plugin surface", { plugin: q.plugin, surface: q.surfaceId, code: q.code });
|
|
2981
3085
|
}
|
|
2982
3086
|
} catch (error) {
|
|
@@ -3066,7 +3170,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3066
3170
|
try {
|
|
3067
3171
|
const { configs, quarantine } = await buildPluginMcpConfigs({ cwd });
|
|
3068
3172
|
for (const q of quarantine) {
|
|
3069
|
-
gjcFindings.add({
|
|
3173
|
+
gjcFindings.add({
|
|
3174
|
+
identity: q.identity,
|
|
3175
|
+
surfaceId: q.surfaceId,
|
|
3176
|
+
code: q.code,
|
|
3177
|
+
message: q.message,
|
|
3178
|
+
decision: "quarantined",
|
|
3179
|
+
provenance: { source: "plugin-bundle", plugin: q.plugin },
|
|
3180
|
+
});
|
|
3070
3181
|
logger.warn("Quarantined GJC plugin MCP", { plugin: q.plugin, surface: q.surfaceId, code: q.code });
|
|
3071
3182
|
}
|
|
3072
3183
|
const pluginNames = new Set(Object.keys(configs));
|
|
@@ -3211,12 +3322,22 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3211
3322
|
// Always-on constrained plugin hooks (validated registry surfaces). Additive
|
|
3212
3323
|
// and a no-op without installed plugins; the loader denies all dangerous APIs.
|
|
3213
3324
|
try {
|
|
3214
|
-
const pluginHookResult = await loadConstrainedPluginHooks({
|
|
3325
|
+
const pluginHookResult = await loadConstrainedPluginHooks({
|
|
3326
|
+
cwd,
|
|
3327
|
+
activationGeneration: gjcActivationGeneration,
|
|
3328
|
+
});
|
|
3215
3329
|
if (pluginHookResult.hooks.length > 0) {
|
|
3216
3330
|
inlineExtensions.push(createPluginHooksExtension(pluginHookResult.hooks));
|
|
3217
3331
|
}
|
|
3218
3332
|
for (const q of pluginHookResult.quarantine) {
|
|
3219
|
-
gjcFindings.add({
|
|
3333
|
+
gjcFindings.add({
|
|
3334
|
+
identity: q.identity,
|
|
3335
|
+
surfaceId: q.surfaceId,
|
|
3336
|
+
code: q.code,
|
|
3337
|
+
message: q.message,
|
|
3338
|
+
decision: "quarantined",
|
|
3339
|
+
provenance: { source: "plugin-bundle", plugin: q.plugin },
|
|
3340
|
+
});
|
|
3220
3341
|
logger.warn("Quarantined GJC plugin hook", { plugin: q.plugin, surface: q.surfaceId, code: q.code });
|
|
3221
3342
|
}
|
|
3222
3343
|
} catch (error) {
|
|
@@ -3776,7 +3897,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3776
3897
|
} else if (!toolRegistry.has("resolve")) {
|
|
3777
3898
|
const resolveTool = await logger.time("createTools:resolve:session", HIDDEN_TOOLS.resolve, toolSession);
|
|
3778
3899
|
if (resolveTool) {
|
|
3779
|
-
const
|
|
3900
|
+
const resolveWithNotice = wrapToolWithMetaNotice(resolveTool);
|
|
3901
|
+
const wrappedResolveTool = extensionRunner
|
|
3902
|
+
? (new ExtensionToolWrapper(resolveWithNotice, extensionRunner) as AgentTool)
|
|
3903
|
+
: resolveWithNotice;
|
|
3780
3904
|
builtinCandidateTools.push(wrappedResolveTool);
|
|
3781
3905
|
toolRegistry.set(wrappedResolveTool.name, wrappedResolveTool);
|
|
3782
3906
|
builtinToolIdentities.add(wrappedResolveTool);
|
|
@@ -3914,6 +4038,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3914
4038
|
// Live cwd: the prompt is rebuilt after a rescope, and describing the
|
|
3915
4039
|
// retired launcher root there is what makes the model pick wrong paths.
|
|
3916
4040
|
cwd: getLiveCwd(),
|
|
4041
|
+
agentDir,
|
|
4042
|
+
profileAuthority,
|
|
3917
4043
|
skills,
|
|
3918
4044
|
contextFiles,
|
|
3919
4045
|
tools: promptTools,
|
|
@@ -3924,6 +4050,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
3924
4050
|
appendSystemPrompt: appendPrompt,
|
|
3925
4051
|
pluginAppendices: pluginSystemAppendices,
|
|
3926
4052
|
repeatToolDescriptions,
|
|
4053
|
+
reasoningLanguage: settings.get("reasoningLanguage"),
|
|
3927
4054
|
intentField,
|
|
3928
4055
|
toolDiscoveryActive: effectiveDiscoveryMode === "all" || mcpDiscoveryEnabled,
|
|
3929
4056
|
eagerTasks: resolveEagerTasks(),
|
|
@@ -4185,21 +4312,21 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
4185
4312
|
if (!obfuscator?.hasSecrets() || !obfuscateMessagesFn) return converted;
|
|
4186
4313
|
return obfuscateMessagesFn(obfuscator, converted);
|
|
4187
4314
|
};
|
|
4188
|
-
const transformContext = async (messages: AgentMessage[],
|
|
4315
|
+
const transformContext = async (messages: AgentMessage[], signal?: AbortSignal, scope?: AttemptScopeRef) => {
|
|
4189
4316
|
// External Agent events dispatch listeners without awaiting them. The
|
|
4190
4317
|
// session-owned barrier makes any pre-admission artifact transformation
|
|
4191
4318
|
// visible before this provider context is normalized.
|
|
4192
4319
|
await session?.awaitPendingContextTransformations();
|
|
4193
|
-
return extensionRunner ? await extensionRunner.emitContext(messages, scope) : messages;
|
|
4320
|
+
return extensionRunner ? await extensionRunner.emitContext(messages, scope, signal) : messages;
|
|
4194
4321
|
};
|
|
4195
4322
|
const onPayload = extensionRunner
|
|
4196
|
-
? async (payload: unknown, _model?: Model, scope?: AttemptScopeRef) => {
|
|
4197
|
-
return await extensionRunner.emitBeforeProviderRequest(payload, scope);
|
|
4323
|
+
? async (payload: unknown, _model?: Model, scope?: AttemptScopeRef, signal?: AbortSignal) => {
|
|
4324
|
+
return await extensionRunner.emitBeforeProviderRequest(payload, scope, signal);
|
|
4198
4325
|
}
|
|
4199
4326
|
: undefined;
|
|
4200
4327
|
const onResponse: SimpleStreamOptions["onResponse"] | undefined = extensionRunner
|
|
4201
|
-
? async (response, model, scope) => {
|
|
4202
|
-
await extensionRunner.emitAfterProviderResponse(response, model, scope);
|
|
4328
|
+
? async (response, model, scope, signal) => {
|
|
4329
|
+
await extensionRunner.emitAfterProviderResponse(response, model, scope, signal);
|
|
4203
4330
|
}
|
|
4204
4331
|
: undefined;
|
|
4205
4332
|
|
|
@@ -4257,6 +4384,32 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
4257
4384
|
).seedNormalizedMessages(options.forkContextSeed.messages);
|
|
4258
4385
|
}
|
|
4259
4386
|
|
|
4387
|
+
const resolvedCredentialScopes = new Map<string, string | undefined>();
|
|
4388
|
+
const resolveAgentApiKey = async (provider: string, signal?: AbortSignal): Promise<string> => {
|
|
4389
|
+
const liveModel = resolveLiveSessionApiKeyModel(sessionAgent?.state.model, model, provider);
|
|
4390
|
+
const hasExplicitScopePolicy =
|
|
4391
|
+
modelRegistry.authStorage.hasSessionCredentialSelector(provider, credentialSessionId) ||
|
|
4392
|
+
modelRegistry.authStorage.hasSessionCredentialAuto(provider, credentialSessionId);
|
|
4393
|
+
const resolution = await lookupSessionApiKey(
|
|
4394
|
+
modelRegistry,
|
|
4395
|
+
provider,
|
|
4396
|
+
credentialSessionId,
|
|
4397
|
+
liveModel,
|
|
4398
|
+
!hasExplicitScopePolicy,
|
|
4399
|
+
signal,
|
|
4400
|
+
);
|
|
4401
|
+
resolvedCredentialScopes.set(provider, resolution.credentialSessionId);
|
|
4402
|
+
return resolution.apiKey;
|
|
4403
|
+
};
|
|
4404
|
+
const resolvedCredentialType = (provider: string): "api_key" | "oauth" | undefined => {
|
|
4405
|
+
const scope = resolvedCredentialScopes.has(provider)
|
|
4406
|
+
? resolvedCredentialScopes.get(provider)
|
|
4407
|
+
: credentialSessionId;
|
|
4408
|
+
return modelRegistry.authStorage.getEffectiveCredentialType(provider, scope, {
|
|
4409
|
+
owner: modelRegistry.getAuthStorageOwner(),
|
|
4410
|
+
});
|
|
4411
|
+
};
|
|
4412
|
+
|
|
4260
4413
|
agent = new Agent({
|
|
4261
4414
|
initialState: {
|
|
4262
4415
|
systemPrompt,
|
|
@@ -4295,44 +4448,42 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
4295
4448
|
shouldPause: options.shouldPause,
|
|
4296
4449
|
preferWebsockets: preferOpenAICodexWebsockets,
|
|
4297
4450
|
getToolContext: tc => toolContextStore.getContext(tc),
|
|
4298
|
-
getApiKey:
|
|
4451
|
+
getApiKey: provider => {
|
|
4299
4452
|
// AgentLoop asks by provider, but the active model carries the
|
|
4300
4453
|
// model-scoped credential selector. Read it at call time so model
|
|
4301
4454
|
// changes are honored after /new, fork, resume, or branch switches.
|
|
4302
|
-
|
|
4303
|
-
const key =
|
|
4304
|
-
liveModel?.provider === provider
|
|
4305
|
-
? await modelRegistry.getApiKey(liveModel, credentialSessionId)
|
|
4306
|
-
: undefined;
|
|
4307
|
-
const providerKey = key ?? (await modelRegistry.getApiKeyForProvider(provider, credentialSessionId));
|
|
4308
|
-
if (!providerKey) {
|
|
4309
|
-
throw new Error(`No API key found for provider "${provider}"`);
|
|
4310
|
-
}
|
|
4311
|
-
return providerKey;
|
|
4455
|
+
return resolveAgentApiKey(provider);
|
|
4312
4456
|
},
|
|
4313
|
-
getAuthCredentialType:
|
|
4457
|
+
getAuthCredentialType: resolvedCredentialType,
|
|
4314
4458
|
streamFn: async (streamModel, context, streamOptions) => {
|
|
4315
4459
|
const requestStartedAt = performance.now();
|
|
4316
4460
|
let stream: Awaited<ReturnType<typeof streamSimple>>;
|
|
4317
4461
|
try {
|
|
4318
|
-
const effectiveApiKey = await modelRegistry.getApiKey(streamModel, credentialSessionId);
|
|
4319
4462
|
stream = await streamSimple(streamModel, context, {
|
|
4320
4463
|
...streamOptions,
|
|
4321
|
-
apiKey: effectiveApiKey,
|
|
4322
|
-
authCredentialType: modelRegistry.getSessionCredentialType(streamModel.provider, credentialSessionId),
|
|
4323
4464
|
onAuthError: async (provider, oldKey, error) => {
|
|
4465
|
+
const resolvedScope = resolvedCredentialScopes.has(provider)
|
|
4466
|
+
? resolvedCredentialScopes.get(provider)
|
|
4467
|
+
: credentialSessionId;
|
|
4324
4468
|
await modelRegistry.authStorage.invalidateCredentialMatching(provider, oldKey, {
|
|
4325
4469
|
signal: streamOptions?.signal,
|
|
4326
|
-
sessionId:
|
|
4470
|
+
sessionId: resolvedScope,
|
|
4327
4471
|
owner: modelRegistry.getAuthStorageOwner(),
|
|
4328
4472
|
});
|
|
4329
4473
|
logger.debug("Retrying provider request after credential invalidation", {
|
|
4330
4474
|
provider,
|
|
4331
4475
|
error: error instanceof Error ? error.message : String(error),
|
|
4332
4476
|
});
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4477
|
+
const replacementApiKey = await resolveAgentApiKey(provider, streamOptions?.signal);
|
|
4478
|
+
if (
|
|
4479
|
+
!isStableSessionApiKeyCredentialType(
|
|
4480
|
+
streamOptions?.authCredentialType,
|
|
4481
|
+
resolvedCredentialType(provider),
|
|
4482
|
+
)
|
|
4483
|
+
) {
|
|
4484
|
+
return undefined;
|
|
4485
|
+
}
|
|
4486
|
+
return replacementApiKey;
|
|
4336
4487
|
},
|
|
4337
4488
|
});
|
|
4338
4489
|
} catch (error) {
|
|
@@ -4459,6 +4610,28 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
4459
4610
|
customCommands: customCommandsResult.commands,
|
|
4460
4611
|
skills,
|
|
4461
4612
|
skillWarnings,
|
|
4613
|
+
reloadSkills:
|
|
4614
|
+
options.skills === undefined
|
|
4615
|
+
? async reloadCwd => {
|
|
4616
|
+
if (!settings.get("skills.enabled")) {
|
|
4617
|
+
return { skills: getEmbeddedDefaultGjcSkills(), warnings: [] };
|
|
4618
|
+
} else {
|
|
4619
|
+
const reloaded = await loadSkills({
|
|
4620
|
+
...settings.getGroup("skills"),
|
|
4621
|
+
agentDir,
|
|
4622
|
+
profileAuthority,
|
|
4623
|
+
cwd: reloadCwd,
|
|
4624
|
+
disabledExtensions: settings.get("disabledExtensions"),
|
|
4625
|
+
});
|
|
4626
|
+
return { skills: withEmbeddedDefaultGjcSkills(reloaded.skills), warnings: reloaded.warnings };
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
: undefined,
|
|
4630
|
+
onSkillsReloaded: (reloadedSkills, reloadedWarnings) => {
|
|
4631
|
+
skills = reloadedSkills;
|
|
4632
|
+
skillWarnings = reloadedWarnings;
|
|
4633
|
+
if (!options.parentTaskPrefix) setActiveSkills(reloadedSkills);
|
|
4634
|
+
},
|
|
4462
4635
|
skillsSettings: settings.getGroup("skills"),
|
|
4463
4636
|
modelRegistry,
|
|
4464
4637
|
taskDepth,
|
|
@@ -56,18 +56,25 @@ function upstreamUrl(url: string, token: string): string {
|
|
|
56
56
|
return endpoint.toString();
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function waitForDrain(stream: Writable): Promise<void
|
|
59
|
+
function waitForDrain(stream: Writable): { promise: Promise<void>; cancel: () => void } {
|
|
60
60
|
const { promise, reject, resolve } = Promise.withResolvers<void>();
|
|
61
|
+
let settled = false;
|
|
61
62
|
const onDrain = (): void => done(resolve);
|
|
62
63
|
const onError = (error: Error): void => done(() => reject(error));
|
|
64
|
+
const onClose = (): void => done(() => reject(new Error("downstream_closed")));
|
|
63
65
|
const done = (callback: () => void): void => {
|
|
66
|
+
if (settled) return;
|
|
67
|
+
settled = true;
|
|
64
68
|
stream.removeListener("drain", onDrain);
|
|
65
69
|
stream.removeListener("error", onError);
|
|
70
|
+
stream.removeListener("close", onClose);
|
|
66
71
|
callback();
|
|
67
72
|
};
|
|
68
73
|
stream.once("drain", onDrain);
|
|
69
74
|
stream.once("error", onError);
|
|
70
|
-
|
|
75
|
+
stream.once("close", onClose);
|
|
76
|
+
if (stream.destroyed) onClose();
|
|
77
|
+
return { promise, cancel: onDrain };
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
const WEBSOCKET_CONNECTING = 0;
|
|
@@ -96,7 +103,9 @@ export async function startRelayPair(options: RelayOptions): Promise<RelayPair>
|
|
|
96
103
|
const finished = Promise.withResolvers<void>();
|
|
97
104
|
let closed = false;
|
|
98
105
|
let completed = false;
|
|
99
|
-
let
|
|
106
|
+
let downstreamChunks: Buffer[] = [];
|
|
107
|
+
let downstreamBytes = 0;
|
|
108
|
+
let downstreamDrain: { promise: Promise<void>; cancel: () => void } | undefined;
|
|
100
109
|
const toWs: QueuedFrame[] = [];
|
|
101
110
|
const toDownstream: QueuedFrame[] = [];
|
|
102
111
|
let pendingToWs = 0;
|
|
@@ -123,6 +132,7 @@ export async function startRelayPair(options: RelayOptions): Promise<RelayPair>
|
|
|
123
132
|
const close = async (error?: Error): Promise<void> => {
|
|
124
133
|
if (closed) return finished.promise.catch(() => undefined);
|
|
125
134
|
closed = true;
|
|
135
|
+
downstreamDrain?.cancel();
|
|
126
136
|
detach();
|
|
127
137
|
options.downstream.pause();
|
|
128
138
|
if (ws.readyState === WEBSOCKET_OPEN || ws.readyState === WEBSOCKET_CONNECTING) ws.close();
|
|
@@ -175,33 +185,45 @@ export async function startRelayPair(options: RelayOptions): Promise<RelayPair>
|
|
|
175
185
|
writingDownstream = true;
|
|
176
186
|
if (frame.accounted) pendingToDownstream -= frame.bytes.length;
|
|
177
187
|
try {
|
|
178
|
-
if (!options.downstreamSink.write(frame.bytes)
|
|
188
|
+
if (!options.downstreamSink.write(frame.bytes) && !closed) {
|
|
189
|
+
downstreamDrain = waitForDrain(options.downstreamSink);
|
|
190
|
+
await downstreamDrain.promise;
|
|
191
|
+
}
|
|
179
192
|
} catch (error) {
|
|
180
193
|
await close(error instanceof Error ? error : new Error(String(error)));
|
|
181
194
|
return;
|
|
182
195
|
} finally {
|
|
196
|
+
downstreamDrain = undefined;
|
|
183
197
|
writingDownstream = false;
|
|
184
198
|
}
|
|
185
199
|
void pumpDownstream();
|
|
186
200
|
};
|
|
187
201
|
const consumeLines = (chunk: Buffer): void => {
|
|
188
|
-
|
|
189
|
-
let newline =
|
|
202
|
+
let start = 0;
|
|
203
|
+
let newline = chunk.indexOf(0x0a);
|
|
190
204
|
while (newline >= 0) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
if (line.length === 0)
|
|
205
|
+
const length = downstreamBytes + newline - start;
|
|
206
|
+
if (length === 0)
|
|
194
207
|
return fail({ type: "transport_error", code: "protocol_error", direction: "downstream->ws" });
|
|
195
|
-
if (
|
|
208
|
+
if (length > REQUEST_FRAME_BYTES)
|
|
196
209
|
return fail({ type: "transport_error", code: "frame_oversize", direction: "downstream->ws" });
|
|
210
|
+
downstreamChunks.push(chunk.subarray(start, newline));
|
|
211
|
+
const line = Buffer.concat(downstreamChunks, length);
|
|
212
|
+
downstreamChunks = [];
|
|
213
|
+
downstreamBytes = 0;
|
|
197
214
|
if (options.validateDownstreamFrame && !options.validateDownstreamFrame(line.toString("utf8")))
|
|
198
215
|
return fail({ type: "transport_error", code: "protocol_error", direction: "downstream->ws" });
|
|
199
216
|
enqueue(toWs, "downstream->ws", line);
|
|
200
217
|
if (closed) return;
|
|
201
|
-
|
|
218
|
+
start = newline + 1;
|
|
219
|
+
newline = chunk.indexOf(0x0a, start);
|
|
220
|
+
}
|
|
221
|
+
if (start < chunk.length) {
|
|
222
|
+
downstreamBytes += chunk.length - start;
|
|
223
|
+
if (downstreamBytes > REQUEST_FRAME_BYTES)
|
|
224
|
+
return fail({ type: "transport_error", code: "frame_oversize", direction: "downstream->ws" });
|
|
225
|
+
downstreamChunks.push(chunk.subarray(start));
|
|
202
226
|
}
|
|
203
|
-
if (downstreamBuffer.length > REQUEST_FRAME_BYTES)
|
|
204
|
-
fail({ type: "transport_error", code: "frame_oversize", direction: "downstream->ws" });
|
|
205
227
|
};
|
|
206
228
|
const onData = (chunk: Buffer | string): void => consumeLines(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
207
229
|
const onEnd = (): void => void close();
|
|
@@ -92,10 +92,10 @@ function brokerSessionRows(sessions: readonly unknown[]): BrokerSessionRow[] {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/** Exhausts strict broker `session.list` pages into one full session snapshot. */
|
|
95
|
-
export async function listBrokerSessions(broker: SdkClient): Promise<BrokerSessionRow[]> {
|
|
95
|
+
export async function listBrokerSessions(broker: SdkClient, explicitSessionId?: string): Promise<BrokerSessionRow[]> {
|
|
96
96
|
try {
|
|
97
97
|
const pages = await traverseSessionList(
|
|
98
|
-
{},
|
|
98
|
+
{ ...(explicitSessionId ? { resolveSessionId: explicitSessionId } : {}) },
|
|
99
99
|
async input => await broker.global("session.list", input),
|
|
100
100
|
response => {
|
|
101
101
|
brokerResult(response);
|
|
@@ -147,7 +147,7 @@ export async function runSdkServe(argv: string[]): Promise<void> {
|
|
|
147
147
|
throw new Error("broker_unavailable: SDK broker is not reachable");
|
|
148
148
|
}
|
|
149
149
|
try {
|
|
150
|
-
const sessionId = selectBrokerSession(await listBrokerSessions(broker), parsed.sessionId);
|
|
150
|
+
const sessionId = selectBrokerSession(await listBrokerSessions(broker, parsed.sessionId), parsed.sessionId);
|
|
151
151
|
const endpoint = brokerResult(await broker.global("session.get_endpoint", { sessionId }));
|
|
152
152
|
const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
|
|
153
153
|
const token = typeof endpoint.token === "string" ? endpoint.token : "";
|