@gajae-code/coding-agent 0.4.2 → 0.4.4
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 +13 -0
- package/dist/types/async/job-manager.d.ts +44 -1
- package/dist/types/cli/setup-cli.d.ts +14 -1
- package/dist/types/commands/coordinator.d.ts +19 -0
- package/dist/types/commands/mcp-serve.d.ts +24 -0
- package/dist/types/commands/setup.d.ts +41 -0
- package/dist/types/commit/model-selection.d.ts +1 -1
- package/dist/types/config/model-registry.d.ts +3 -1
- package/dist/types/config/model-resolver.d.ts +1 -19
- package/dist/types/config/models-config-schema.d.ts +12 -0
- package/dist/types/config/settings-schema.d.ts +15 -1
- package/dist/types/coordinator/contract.d.ts +4 -0
- package/dist/types/coordinator-mcp/policy.d.ts +24 -0
- package/dist/types/coordinator-mcp/safety.d.ts +26 -0
- package/dist/types/coordinator-mcp/server.d.ts +52 -0
- package/dist/types/extensibility/extensions/types.d.ts +13 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +8 -1
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
- package/dist/types/harness-control-plane/types.d.ts +7 -2
- package/dist/types/modes/acp/acp-event-mapper.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +7 -0
- package/dist/types/modes/components/hook-selector.d.ts +11 -0
- package/dist/types/modes/shared/agent-wire/command-contract.d.ts +18 -0
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +84 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +14 -7
- package/dist/types/modes/shared/agent-wire/event-observation.d.ts +37 -0
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +13 -34
- package/dist/types/session/agent-session.d.ts +12 -1
- package/dist/types/session/session-manager.d.ts +1 -1
- package/dist/types/setup/hermes-setup.d.ts +71 -0
- package/dist/types/task/render.d.ts +7 -1
- package/dist/types/tools/bash.d.ts +2 -0
- package/dist/types/tools/browser/actions.d.ts +54 -0
- package/dist/types/tools/browser.d.ts +80 -0
- package/dist/types/tools/image-gen.d.ts +1 -0
- package/dist/types/tools/index.d.ts +3 -1
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/subagent-render.d.ts +25 -0
- package/dist/types/tools/subagent.d.ts +5 -1
- package/package.json +7 -7
- package/src/async/job-manager.ts +163 -2
- package/src/cli/setup-cli.ts +86 -2
- package/src/cli.ts +2 -0
- package/src/commands/coordinator.ts +70 -0
- package/src/commands/mcp-serve.ts +62 -0
- package/src/commands/setup.ts +30 -1
- package/src/commands/ultragoal.ts +7 -1
- package/src/commit/agentic/index.ts +2 -2
- package/src/commit/model-selection.ts +7 -22
- package/src/commit/pipeline.ts +2 -2
- package/src/config/model-registry.ts +17 -9
- package/src/config/model-resolver.ts +14 -84
- package/src/config/models-config-schema.ts +2 -0
- package/src/config/settings-schema.ts +14 -1
- package/src/coordinator/contract.ts +20 -0
- package/src/coordinator-mcp/policy.ts +160 -0
- package/src/coordinator-mcp/safety.ts +80 -0
- package/src/coordinator-mcp/server.ts +1316 -0
- package/src/extensibility/extensions/types.ts +13 -0
- package/src/gjc-runtime/goal-mode-request.ts +21 -1
- package/src/gjc-runtime/session-state-sidecar.ts +79 -0
- package/src/harness-control-plane/owner.ts +3 -3
- package/src/harness-control-plane/rpc-adapter.ts +7 -1
- package/src/harness-control-plane/types.ts +8 -11
- package/src/internal-urls/docs-index.generated.ts +6 -5
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-agent.ts +17 -9
- package/src/modes/acp/acp-event-mapper.ts +33 -1
- package/src/modes/components/custom-editor.ts +19 -3
- package/src/modes/components/hook-selector.ts +109 -5
- package/src/modes/controllers/extension-ui-controller.ts +16 -1
- package/src/modes/controllers/input-controller.ts +27 -7
- package/src/modes/controllers/selector-controller.ts +7 -1
- package/src/modes/interactive-mode.ts +3 -1
- package/src/modes/rpc/rpc-client.ts +16 -3
- package/src/modes/rpc/rpc-mode.ts +5 -2
- package/src/modes/shared/agent-wire/command-contract.ts +18 -0
- package/src/modes/shared/agent-wire/event-contract.ts +147 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +35 -16
- package/src/modes/shared/agent-wire/event-observation.ts +397 -0
- package/src/modes/shared/agent-wire/protocol.ts +24 -81
- package/src/modes/utils/context-usage.ts +2 -2
- package/src/prompts/agents/architect.md +6 -0
- package/src/prompts/agents/critic.md +6 -0
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/plan.md +1 -1
- package/src/prompts/agents/planner.md +8 -1
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/tools/browser.md +3 -2
- package/src/runtime-mcp/manager.ts +15 -2
- package/src/sdk.ts +3 -1
- package/src/session/agent-session.ts +66 -4
- package/src/session/session-manager.ts +1 -1
- package/src/setup/hermes/templates/operator-instructions.v1.md +29 -0
- package/src/setup/hermes-setup.ts +429 -0
- package/src/task/agents.ts +1 -1
- package/src/task/index.ts +2 -0
- package/src/task/render.ts +14 -0
- package/src/tools/ask.ts +30 -10
- package/src/tools/bash.ts +6 -1
- package/src/tools/browser/actions.ts +189 -0
- package/src/tools/browser.ts +91 -1
- package/src/tools/image-gen.ts +42 -15
- package/src/tools/index.ts +7 -1
- package/src/tools/inspect-image.ts +10 -8
- package/src/tools/job.ts +12 -2
- package/src/tools/monitor.ts +98 -17
- package/src/tools/renderers.ts +2 -0
- package/src/tools/subagent-render.ts +160 -0
- package/src/tools/subagent.ts +49 -7
- package/src/utils/commit-message-generator.ts +6 -13
- package/src/utils/title-generator.ts +1 -1
- package/dist/types/harness-control-plane/frame-mapper.d.ts +0 -29
- package/src/harness-control-plane/frame-mapper.ts +0 -286
- package/src/priority.json +0 -37
|
@@ -1,100 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared agent-wire protocol primitives for GJC bridge surfaces.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* and `.gjc/plans/ralplan/gjc-backend-bridge/pending-approval.md`.
|
|
4
|
+
* The canonical event/frame contract now lives in `event-contract.ts`. This
|
|
5
|
+
* module re-exports it under the historical `Bridge*` names so existing RPC and
|
|
6
|
+
* Bridge code keeps compiling while the adapters migrate to the canonical
|
|
7
|
+
* `AgentWire*` names. See `.gjc/specs/deep-interview-reconcile-rpc-adapters.md`.
|
|
9
8
|
*/
|
|
10
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
AgentWireEventFrame,
|
|
11
|
+
AgentWireEventPayload,
|
|
12
|
+
AgentWireEventType,
|
|
13
|
+
AgentWireFrameEnvelope,
|
|
14
|
+
AgentWireFrameType,
|
|
15
|
+
} from "./event-contract";
|
|
16
|
+
import { AGENT_WIRE_EVENT_TYPES, AGENT_WIRE_PROTOCOL_VERSION } from "./event-contract";
|
|
11
17
|
|
|
12
18
|
/** Wire protocol version. Bump on breaking envelope/semantic changes. */
|
|
13
|
-
export const BRIDGE_PROTOCOL_VERSION =
|
|
19
|
+
export const BRIDGE_PROTOCOL_VERSION = AGENT_WIRE_PROTOCOL_VERSION;
|
|
14
20
|
|
|
15
21
|
/** The discriminant of every `AgentSessionEvent` the agent can emit. */
|
|
16
|
-
export type AgentSessionEventType =
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Compile-time exhaustive registry of every `AgentSessionEvent` variant.
|
|
20
|
-
*
|
|
21
|
-
* Adding a new variant to `AgentSessionEvent` without registering it here is a
|
|
22
|
-
* type error. This keeps the bridge wire surface in lockstep with the agent
|
|
23
|
-
* event union — the "event/element drift → silent incompleteness" mitigation
|
|
24
|
-
* from the plan's pre-mortem.
|
|
25
|
-
*/
|
|
26
|
-
const AGENT_SESSION_EVENT_TYPE_REGISTRY: Record<AgentSessionEventType, true> = {
|
|
27
|
-
agent_start: true,
|
|
28
|
-
agent_end: true,
|
|
29
|
-
turn_start: true,
|
|
30
|
-
turn_end: true,
|
|
31
|
-
message_start: true,
|
|
32
|
-
message_update: true,
|
|
33
|
-
message_end: true,
|
|
34
|
-
tool_execution_start: true,
|
|
35
|
-
tool_execution_update: true,
|
|
36
|
-
tool_execution_end: true,
|
|
37
|
-
auto_compaction_start: true,
|
|
38
|
-
auto_compaction_end: true,
|
|
39
|
-
auto_retry_start: true,
|
|
40
|
-
auto_retry_end: true,
|
|
41
|
-
retry_fallback_applied: true,
|
|
42
|
-
retry_fallback_succeeded: true,
|
|
43
|
-
ttsr_triggered: true,
|
|
44
|
-
todo_reminder: true,
|
|
45
|
-
todo_auto_clear: true,
|
|
46
|
-
irc_message: true,
|
|
47
|
-
notice: true,
|
|
48
|
-
thinking_level_changed: true,
|
|
49
|
-
goal_updated: true,
|
|
50
|
-
};
|
|
22
|
+
export type AgentSessionEventType = AgentWireEventType;
|
|
51
23
|
|
|
52
24
|
/** Every agent-session event type, derived from the exhaustive registry. */
|
|
53
|
-
export const AGENT_SESSION_EVENT_TYPES: readonly AgentSessionEventType[] =
|
|
54
|
-
AGENT_SESSION_EVENT_TYPE_REGISTRY,
|
|
55
|
-
) as AgentSessionEventType[];
|
|
25
|
+
export const AGENT_SESSION_EVENT_TYPES: readonly AgentSessionEventType[] = AGENT_WIRE_EVENT_TYPES;
|
|
56
26
|
|
|
57
27
|
/** Top-level frame categories carried over any bridge transport. */
|
|
58
|
-
export type BridgeFrameType =
|
|
59
|
-
| "ready"
|
|
60
|
-
| "event"
|
|
61
|
-
| "response"
|
|
62
|
-
| "ui_request"
|
|
63
|
-
| "permission_request"
|
|
64
|
-
| "host_tool_call"
|
|
65
|
-
| "host_uri_request"
|
|
66
|
-
| "reset"
|
|
67
|
-
| "workflow_gate"
|
|
68
|
-
| "error";
|
|
28
|
+
export type BridgeFrameType = AgentWireFrameType;
|
|
69
29
|
|
|
70
|
-
/**
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
* an additive, non-breaking change later.
|
|
76
|
-
*/
|
|
77
|
-
export interface BridgeFrameEnvelope<TType extends BridgeFrameType = BridgeFrameType, TPayload = unknown> {
|
|
78
|
-
protocol_version: typeof BRIDGE_PROTOCOL_VERSION;
|
|
79
|
-
session_id: string;
|
|
80
|
-
/** Monotonic per-session sequence number, starting at 1. */
|
|
81
|
-
seq: number;
|
|
82
|
-
/** Unique id for this frame. */
|
|
83
|
-
frame_id: string;
|
|
84
|
-
/** Ties a request frame to its response frame, when applicable. */
|
|
85
|
-
correlation_id?: string;
|
|
86
|
-
type: TType;
|
|
87
|
-
payload: TPayload;
|
|
88
|
-
}
|
|
30
|
+
/** Universal frame envelope. See {@link AgentWireFrameEnvelope}. */
|
|
31
|
+
export type BridgeFrameEnvelope<
|
|
32
|
+
TType extends BridgeFrameType = BridgeFrameType,
|
|
33
|
+
TPayload = unknown,
|
|
34
|
+
> = AgentWireFrameEnvelope<TType, TPayload>;
|
|
89
35
|
|
|
90
|
-
/** Payload carried by an `event` frame. */
|
|
91
|
-
export
|
|
92
|
-
event_type: AgentSessionEventType;
|
|
93
|
-
event: AgentSessionEvent;
|
|
94
|
-
}
|
|
36
|
+
/** Payload carried by an `event` frame. See {@link AgentWireEventPayload}. */
|
|
37
|
+
export type BridgeEventPayload = AgentWireEventPayload;
|
|
95
38
|
|
|
96
39
|
/** An `AgentSessionEvent` serialized into a versioned wire frame. */
|
|
97
|
-
export type BridgeEventFrame =
|
|
40
|
+
export type BridgeEventFrame = AgentWireEventFrame;
|
|
98
41
|
|
|
99
42
|
/** A `workflow_gate` event serialized into a versioned wire frame (#321). */
|
|
100
43
|
export type BridgeWorkflowGateFrame = BridgeFrameEnvelope<
|
|
@@ -197,14 +197,14 @@ export function computeContextBreakdown(
|
|
|
197
197
|
if (contextWindow > 0) {
|
|
198
198
|
const compactionSettings = session.settings.getGroup("compaction") as CompactionSettings;
|
|
199
199
|
if (compactionSettings.enabled && compactionSettings.strategy !== "off") {
|
|
200
|
-
const threshold = resolveThresholdTokens(contextWindow, compactionSettings);
|
|
200
|
+
const threshold = resolveThresholdTokens(contextWindow, compactionSettings, model?.maxTokens ?? 0);
|
|
201
201
|
autoCompactBufferTokens = Math.max(0, contextWindow - threshold);
|
|
202
202
|
} else {
|
|
203
203
|
autoCompactBufferTokens = 0;
|
|
204
204
|
}
|
|
205
205
|
// Even when fully disabled, fall back to a sensible reserve floor for display.
|
|
206
206
|
if (autoCompactBufferTokens === 0 && compactionSettings.enabled) {
|
|
207
|
-
autoCompactBufferTokens = effectiveReserveTokens(contextWindow, compactionSettings);
|
|
207
|
+
autoCompactBufferTokens = effectiveReserveTokens(contextWindow, compactionSettings, model?.maxTokens ?? 0);
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
autoCompactBufferTokens = Math.min(autoCompactBufferTokens, Math.max(0, contextWindow - usedTokens));
|
|
@@ -83,4 +83,10 @@ Prioritized concrete actions.
|
|
|
83
83
|
|
|
84
84
|
## Trade-offs
|
|
85
85
|
Table or bullets comparing viable options when relevant.
|
|
86
|
+
|
|
87
|
+
Persist this full review as the durable artifact via the restricted bash CLI, passing the markdown inline (never a file path, never `/tmp`):
|
|
88
|
+
|
|
89
|
+
gjc ralplan --write --stage architect --stage_n <N> --artifact "<full review markdown>" --json
|
|
90
|
+
|
|
91
|
+
Then return to the caller ONLY the write receipt (`run_id`, `path`, `sha256`, `stage`, `stage_n`) plus the compact verdict (Architectural Status + Code Review Recommendation). Never paste the full review body back into your response — the caller reads the persisted artifact when it needs the full text.
|
|
86
92
|
</output_contract>
|
|
@@ -56,4 +56,10 @@ Review plan clarity, completeness, verification, big-picture fit, referenced fil
|
|
|
56
56
|
- Risk/Verification Rigor
|
|
57
57
|
|
|
58
58
|
If not OKAY, list concrete required fixes.
|
|
59
|
+
|
|
60
|
+
Persist this full evaluation as the durable artifact via the restricted bash CLI, passing the markdown inline (never a file path, never `/tmp`):
|
|
61
|
+
|
|
62
|
+
gjc ralplan --write --stage critic --stage_n <N> --artifact "<full evaluation markdown>" --json
|
|
63
|
+
|
|
64
|
+
Then return to the caller ONLY the write receipt (`run_id`, `path`, `sha256`, `stage`, `stage_n`) plus the compact verdict (OKAY / ITERATE / REJECT). Never paste the full evaluation body back into your response — the caller reads the persisted artifact when it needs the full text.
|
|
59
65
|
</output_contract>
|
|
@@ -3,7 +3,7 @@ name: plan
|
|
|
3
3
|
description: Software architect for complex multi-file architectural decisions. NOT for simple tasks, single-file changes, or tasks completable in <5 tool calls.
|
|
4
4
|
tools: read, search, find, bash, lsp, web_search, ast_grep
|
|
5
5
|
spawns: explore
|
|
6
|
-
model: pi/
|
|
6
|
+
model: pi/default
|
|
7
7
|
thinking-level: high
|
|
8
8
|
hide: true
|
|
9
9
|
---
|
|
@@ -18,6 +18,7 @@ Leave execution with a right-sized, evidence-grounded plan: scope, steps, accept
|
|
|
18
18
|
<constraints>
|
|
19
19
|
- Read-only: never write, edit, format, commit, push, or mutate files.
|
|
20
20
|
- Exception: you may use the restricted `bash` tool only for sanctioned GJC workflow CLI persistence (`gjc ralplan --write ...`) and GJC workflow state read/write/contract commands (`gjc state ...`). For `gjc ralplan --write`, pass the plan markdown inline in `--artifact`, not as a file path. Do not use bash for product-source writes, direct handoffs, state clears, or general shell work.
|
|
21
|
+
- Persist durable plans only through `gjc ralplan --write`. Never write plan files to `/tmp`, the repository, or any other path, and never rely on a file the caller must read back. The CLI is your only persistence channel.
|
|
21
22
|
- Inspect the repository before asking about code facts.
|
|
22
23
|
- Ask only about priorities, tradeoffs, scope decisions, timelines, or preferences that repository inspection cannot resolve.
|
|
23
24
|
- Right-size the step count to the task; do not default to a fixed number of steps.
|
|
@@ -42,7 +43,7 @@ Leave execution with a right-sized, evidence-grounded plan: scope, steps, accept
|
|
|
42
43
|
</success_criteria>
|
|
43
44
|
|
|
44
45
|
<output_contract>
|
|
45
|
-
|
|
46
|
+
Build the full plan as a single markdown document containing:
|
|
46
47
|
- Summary
|
|
47
48
|
- In scope / out of scope
|
|
48
49
|
- File-level changes
|
|
@@ -50,4 +51,10 @@ Return:
|
|
|
50
51
|
- Acceptance criteria
|
|
51
52
|
- Verification
|
|
52
53
|
- Risks and mitigations
|
|
54
|
+
|
|
55
|
+
Persist that markdown as the durable artifact via the restricted bash CLI, passing the plan inline (never a file path, never `/tmp`):
|
|
56
|
+
|
|
57
|
+
gjc ralplan --write --stage planner --stage_n <N> --artifact "<full plan markdown>" --json
|
|
58
|
+
|
|
59
|
+
Then return to the caller ONLY the write receipt (`run_id`, `path`, `sha256`, `stage`, `stage_n`) plus a compact plan summary (<=10 lines). Never paste the full plan body back into your response — the caller reads the persisted artifact when it needs the full text.
|
|
53
60
|
</output_contract>
|
|
@@ -2,10 +2,11 @@ Drives a real Chromium tab with full puppeteer access via JS execution.
|
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
- For static web content (articles, docs, issues/PRs, JSON, PDFs, feeds), prefer the `read` tool with a URL — reader-mode text without spinning up a browser. Use this tool when you need JS execution, authentication, or interactive actions.
|
|
5
|
-
-
|
|
5
|
+
- Four actions:
|
|
6
6
|
- `open` — acquire (or reuse) a named tab. `name` defaults to `"main"`. Optional `url` navigates after the tab is ready. Optional `viewport` sets dimensions. Optional `dialogs: "accept" | "dismiss"` auto-handles `alert`/`confirm`/`beforeunload` so navigation/clicks don't hang (default: leave dialogs unhandled — page hangs until caller wires `page.on('dialog', …)`).
|
|
7
7
|
- `close` — release a tab by `name`, or every tab with `all: true`. For spawned-app browsers, set `kill: true` to terminate the process tree (default leaves it running).
|
|
8
8
|
- `run` — execute JS against an existing tab. `code` is the body of an async function with `page`, `browser`, `tab`, `display`, `assert`, `wait` in scope. The function's return value is JSON-stringified into the tool result; multiple `display(value)` calls accumulate text/images.
|
|
9
|
+
- `act` — run a list of structured `actions` against an existing tab without writing JS (preferred for routine navigation/interaction). Each step is `{ verb, … }`; verbs: `navigate {url, wait_until?}`, `click {id|selector}`, `type {id|selector, text}`, `fill {selector, value}`, `select {selector, values}`, `press {key, selector?}`, `scroll {dx?, dy?}`, `back`, `wait {selector?|ms?}`, `observe {viewport_only?, include_all?}`, `extract {format?}`, `screenshot`. Address elements by the numeric `id` from a prior `observe` (preferred) or a selector. Steps run in order; the tool returns an array of per-step results (observations/extracted content included). Use `run` only when a verb does not cover what you need.
|
|
9
10
|
- Tabs survive across `run` calls and across in-process subagents. Open once, reuse many times.
|
|
10
11
|
- Browser kinds, selected by the `app` field on `open`:
|
|
11
12
|
- default (no `app`) → headless Chromium with stealth patches.
|
|
@@ -32,7 +33,7 @@ Drives a real Chromium tab with full puppeteer access via JS execution.
|
|
|
32
33
|
</instruction>
|
|
33
34
|
|
|
34
35
|
<critical>
|
|
35
|
-
- You MUST call `open` before `run
|
|
36
|
+
- You MUST call `open` before `run` or `act`. Neither implicitly creates a tab.
|
|
36
37
|
- You NEVER screenshot just to "see what's on the page" — `tab.observe()` returns structured data with element ids you can act on immediately.
|
|
37
38
|
- After a `tab.goto()` or any navigation, prior element ids from `tab.observe()` are invalidated. Re-observe before referencing them.
|
|
38
39
|
- `code` runs with full Node access. Treat it as your code, not sandboxed code.
|
|
@@ -304,6 +304,7 @@ export class MCPManager {
|
|
|
304
304
|
config: MCPServerConfig;
|
|
305
305
|
tracked: TrackedPromise<ToolLoadResult>;
|
|
306
306
|
toolsPromise: Promise<ToolLoadResult>;
|
|
307
|
+
connectionAbort: AbortController;
|
|
307
308
|
};
|
|
308
309
|
|
|
309
310
|
const errors = new Map<string, string>();
|
|
@@ -424,7 +425,7 @@ export class MCPManager {
|
|
|
424
425
|
this.#pendingToolLoads.set(name, toolsPromise);
|
|
425
426
|
|
|
426
427
|
const tracked = trackPromise(toolsPromise);
|
|
427
|
-
connectionTasks.push({ name, config, tracked, toolsPromise });
|
|
428
|
+
connectionTasks.push({ name, config, tracked, toolsPromise, connectionAbort });
|
|
428
429
|
|
|
429
430
|
void toolsPromise
|
|
430
431
|
.then(async ({ connection, serverTools }) => {
|
|
@@ -475,7 +476,19 @@ export class MCPManager {
|
|
|
475
476
|
|
|
476
477
|
const pendingWithoutCache = pendingTasks.filter(task => !cachedTools.has(task.name));
|
|
477
478
|
if (pendingWithoutCache.length > 0) {
|
|
478
|
-
|
|
479
|
+
for (const task of pendingWithoutCache) {
|
|
480
|
+
const message = `MCP server connection timed out during startup: ${task.name}`;
|
|
481
|
+
errors.set(task.name, message);
|
|
482
|
+
reportedErrors.add(task.name);
|
|
483
|
+
task.connectionAbort.abort(new Error(message));
|
|
484
|
+
if (this.#pendingConnections.has(task.name)) this.#pendingConnections.delete(task.name);
|
|
485
|
+
if (this.#pendingToolLoads.get(task.name) === task.toolsPromise)
|
|
486
|
+
this.#pendingToolLoads.delete(task.name);
|
|
487
|
+
this.#pendingConnectionControllers.delete(task.name);
|
|
488
|
+
}
|
|
489
|
+
// Do not await these promises here: a misbehaving stdio/MCP transport can ignore
|
|
490
|
+
// AbortSignal and keep startup blocked indefinitely. The background toolsPromise
|
|
491
|
+
// handler will clean up if it eventually settles.
|
|
479
492
|
}
|
|
480
493
|
}
|
|
481
494
|
|
package/src/sdk.ts
CHANGED
|
@@ -868,7 +868,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
868
868
|
imageProvider === "auto" ||
|
|
869
869
|
imageProvider === "openai" ||
|
|
870
870
|
imageProvider === "gemini" ||
|
|
871
|
-
imageProvider === "openrouter"
|
|
871
|
+
imageProvider === "openrouter" ||
|
|
872
|
+
imageProvider === "antigravity"
|
|
872
873
|
) {
|
|
873
874
|
setPreferredImageProvider(imageProvider);
|
|
874
875
|
}
|
|
@@ -1222,6 +1223,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1222
1223
|
timestamp: Date.now(),
|
|
1223
1224
|
}),
|
|
1224
1225
|
sendCustomMessage: (msg, opts) => session.sendCustomMessage(msg, opts),
|
|
1226
|
+
purgeQueuedCustomMessages: predicate => session.purgeQueuedCustomMessages(predicate),
|
|
1225
1227
|
peekQueueInvoker: () => session.peekQueueInvoker(),
|
|
1226
1228
|
peekStandingResolveHandler: () => session.peekStandingResolveHandler(),
|
|
1227
1229
|
setStandingResolveHandler: handler => session.setStandingResolveHandler(handler),
|
|
@@ -89,6 +89,15 @@ export interface ForkContextSeedMetadata {
|
|
|
89
89
|
skippedReasons: Record<string, number>;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
export interface PurgeQueuedCustomMessagesResult {
|
|
93
|
+
agentSteering: number;
|
|
94
|
+
agentFollowUp: number;
|
|
95
|
+
pendingNextTurn: number;
|
|
96
|
+
displaySteering: number;
|
|
97
|
+
displayFollowUp: number;
|
|
98
|
+
totalExecutable: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
92
101
|
export interface ForkContextSeed {
|
|
93
102
|
messages: Message[];
|
|
94
103
|
agentMessages: AgentMessage[];
|
|
@@ -171,6 +180,7 @@ import type { HookCommandContext } from "../extensibility/hooks/types";
|
|
|
171
180
|
import type { Skill, SkillWarning } from "../extensibility/skills";
|
|
172
181
|
import { expandSlashCommand, type FileSlashCommand } from "../extensibility/slash-commands";
|
|
173
182
|
import { buildGjcRuntimeSessionEnv, consumePendingGoalModeRequest } from "../gjc-runtime/goal-mode-request";
|
|
183
|
+
import { persistCoordinatorRuntimeStateFromEvent } from "../gjc-runtime/session-state-sidecar";
|
|
174
184
|
import { writeArtifact } from "../gjc-runtime/state-writer";
|
|
175
185
|
import { requestGjcWorkerIntegrationAttempt } from "../gjc-runtime/team-runtime";
|
|
176
186
|
import { GoalRuntime } from "../goals/runtime";
|
|
@@ -1617,6 +1627,11 @@ export class AgentSession {
|
|
|
1617
1627
|
}
|
|
1618
1628
|
|
|
1619
1629
|
async #emitSessionEvent(event: AgentSessionEvent): Promise<void> {
|
|
1630
|
+
await persistCoordinatorRuntimeStateFromEvent(event, {
|
|
1631
|
+
sessionId: this.sessionId,
|
|
1632
|
+
cwd: this.sessionManager.getCwd(),
|
|
1633
|
+
sessionFile: this.sessionManager.getSessionFile(),
|
|
1634
|
+
});
|
|
1620
1635
|
if (event.type === "message_update") {
|
|
1621
1636
|
this.#emit(event);
|
|
1622
1637
|
void this.#queueExtensionEvent(event);
|
|
@@ -4363,7 +4378,10 @@ export class AgentSession {
|
|
|
4363
4378
|
|
|
4364
4379
|
async #activatePendingGjcGoalModeRequest(): Promise<boolean> {
|
|
4365
4380
|
if (!this.settings.get("goal.enabled")) return false;
|
|
4366
|
-
const pendingGoal = await consumePendingGoalModeRequest(
|
|
4381
|
+
const pendingGoal = await consumePendingGoalModeRequest(
|
|
4382
|
+
this.sessionManager.getCwd(),
|
|
4383
|
+
this.sessionManager.getSessionId(),
|
|
4384
|
+
);
|
|
4367
4385
|
if (!pendingGoal) return false;
|
|
4368
4386
|
const currentState = this.getGoalModeState();
|
|
4369
4387
|
if (currentState?.goal && currentState.goal.status !== "complete" && currentState.goal.status !== "dropped") {
|
|
@@ -5058,6 +5076,10 @@ export class AgentSession {
|
|
|
5058
5076
|
this.#queueHiddenNextTurnMessage(message, true);
|
|
5059
5077
|
}
|
|
5060
5078
|
|
|
5079
|
+
queueDeferredMessageForTests(message: CustomMessage, triggerTurn = true): void {
|
|
5080
|
+
this.#queueHiddenNextTurnMessage(message, triggerTurn);
|
|
5081
|
+
}
|
|
5082
|
+
|
|
5061
5083
|
#queueHiddenNextTurnMessage(message: CustomMessage, triggerTurn: boolean): void {
|
|
5062
5084
|
this.#pendingNextTurnMessages.push(message);
|
|
5063
5085
|
if (!triggerTurn) return;
|
|
@@ -5230,6 +5252,46 @@ export class AgentSession {
|
|
|
5230
5252
|
);
|
|
5231
5253
|
}
|
|
5232
5254
|
|
|
5255
|
+
/** Remove undelivered queued custom messages matching `predicate` from executable queues and tagged display mirrors. */
|
|
5256
|
+
purgeQueuedCustomMessages(predicate: (message: CustomMessage) => boolean): PurgeQueuedCustomMessagesResult {
|
|
5257
|
+
const isMatch = (m: AgentMessage): boolean => m.role === "custom" && predicate(m as CustomMessage);
|
|
5258
|
+
const removedTags = new Set<string>();
|
|
5259
|
+
for (const m of [...this.agent.snapshotSteering(), ...this.agent.snapshotFollowUp()]) {
|
|
5260
|
+
if (isMatch(m)) {
|
|
5261
|
+
const tag = readPendingDisplayTag((m as CustomMessage).details);
|
|
5262
|
+
if (tag) removedTags.add(tag);
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
const agentRemoved = this.agent.removeQueuedMessages(isMatch);
|
|
5266
|
+
const beforeNext = this.#pendingNextTurnMessages.length;
|
|
5267
|
+
for (const m of this.#pendingNextTurnMessages) {
|
|
5268
|
+
if (predicate(m)) {
|
|
5269
|
+
const tag = readPendingDisplayTag(m.details);
|
|
5270
|
+
if (tag) removedTags.add(tag);
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
this.#pendingNextTurnMessages = this.#pendingNextTurnMessages.filter(m => !predicate(m));
|
|
5274
|
+
const pendingNextTurn = beforeNext - this.#pendingNextTurnMessages.length;
|
|
5275
|
+
let displaySteering = 0;
|
|
5276
|
+
let displayFollowUp = 0;
|
|
5277
|
+
if (removedTags.size > 0) {
|
|
5278
|
+
const beforeS = this.#steeringMessages.length;
|
|
5279
|
+
this.#steeringMessages = this.#steeringMessages.filter(e => !(e.tag && removedTags.has(e.tag)));
|
|
5280
|
+
displaySteering = beforeS - this.#steeringMessages.length;
|
|
5281
|
+
const beforeF = this.#followUpMessages.length;
|
|
5282
|
+
this.#followUpMessages = this.#followUpMessages.filter(e => !(e.tag && removedTags.has(e.tag)));
|
|
5283
|
+
displayFollowUp = beforeF - this.#followUpMessages.length;
|
|
5284
|
+
}
|
|
5285
|
+
return {
|
|
5286
|
+
agentSteering: agentRemoved.steering,
|
|
5287
|
+
agentFollowUp: agentRemoved.followUp,
|
|
5288
|
+
pendingNextTurn,
|
|
5289
|
+
displaySteering,
|
|
5290
|
+
displayFollowUp,
|
|
5291
|
+
totalExecutable: agentRemoved.total + pendingNextTurn,
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5294
|
+
|
|
5233
5295
|
/**
|
|
5234
5296
|
* Send a user message to the agent.
|
|
5235
5297
|
* When deliverAs is set, queue the message instead of starting a new turn.
|
|
@@ -5704,7 +5766,7 @@ export class AgentSession {
|
|
|
5704
5766
|
/**
|
|
5705
5767
|
* Cycle through configured role models in a fixed order.
|
|
5706
5768
|
* Skips missing roles.
|
|
5707
|
-
* @param roleOrder - Order of roles to cycle through (e.g., ["
|
|
5769
|
+
* @param roleOrder - Order of roles to cycle through (e.g., ["default"])
|
|
5708
5770
|
* @param options - Optional settings: `temporary` to not persist to settings
|
|
5709
5771
|
*/
|
|
5710
5772
|
async cycleRoleModels(
|
|
@@ -6450,7 +6512,7 @@ export class AgentSession {
|
|
|
6450
6512
|
if (pruneResult) {
|
|
6451
6513
|
contextTokens = Math.max(0, contextTokens - pruneResult.tokensSaved);
|
|
6452
6514
|
}
|
|
6453
|
-
if (shouldCompact(contextTokens, contextWindow, compactionSettings)) {
|
|
6515
|
+
if (shouldCompact(contextTokens, contextWindow, compactionSettings, this.model?.maxTokens ?? 0)) {
|
|
6454
6516
|
// Try promotion first — if a larger model is available, switch instead of compacting
|
|
6455
6517
|
const promoted = await this.#tryContextPromotion(assistantMessage);
|
|
6456
6518
|
if (!promoted) {
|
|
@@ -7086,7 +7148,7 @@ export class AgentSession {
|
|
|
7086
7148
|
}
|
|
7087
7149
|
return new Error(
|
|
7088
7150
|
`Compaction requires usable credentials for ${currentModel.provider}/${currentModel.id}. ` +
|
|
7089
|
-
`Configure ${currentModel.provider} credentials or assign an authenticated fallback
|
|
7151
|
+
`Configure ${currentModel.provider} credentials or assign an authenticated fallback via modelRoles.default.`,
|
|
7090
7152
|
);
|
|
7091
7153
|
}
|
|
7092
7154
|
|
|
@@ -104,7 +104,7 @@ export interface ModelChangeEntry extends SessionEntryBase {
|
|
|
104
104
|
type: "model_change";
|
|
105
105
|
/** Model in "provider/modelId" format */
|
|
106
106
|
model: string;
|
|
107
|
-
/** Role: "default"
|
|
107
|
+
/** Role: "default" or an agent role. Undefined treated as "default" */
|
|
108
108
|
role?: string;
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# GJC Hermes operator instructions v{{TEMPLATE_VERSION}}
|
|
2
|
+
|
|
3
|
+
Server key: {{SERVER_KEY}}
|
|
4
|
+
|
|
5
|
+
These instructions teach a Hermes-style coordinator how to operate GJC through the `{{TOOL_PREFIX}}_*` MCP tools. They are setup guidance, not a GJC workflow skill.
|
|
6
|
+
|
|
7
|
+
## Core loop
|
|
8
|
+
|
|
9
|
+
1. Use `{{TOOL_PREFIX}}_list_sessions` to find an existing session, or `{{TOOL_PREFIX}}_start_session` when a new session is required and mutation is enabled.
|
|
10
|
+
2. Send exactly one bounded task prompt with `{{TOOL_PREFIX}}_send_prompt`.
|
|
11
|
+
3. Store the returned `turn_id`.
|
|
12
|
+
4. Poll `{{TOOL_PREFIX}}_read_turn` or `{{TOOL_PREFIX}}_await_turn` for that `turn_id` until the turn is terminal.
|
|
13
|
+
5. If GJC asks a structured question, use `{{TOOL_PREFIX}}_list_questions` and answer with `{{TOOL_PREFIX}}_submit_question_answer`.
|
|
14
|
+
6. Use `{{TOOL_PREFIX}}_report_status` for coordinator-visible status and final reports.
|
|
15
|
+
7. Use `{{TOOL_PREFIX}}_read_tail` only as advisory debug output when structured turn state is insufficient.
|
|
16
|
+
|
|
17
|
+
Do not report completion to the user until the GJC turn is terminal. Do not infer completion from terminal scrollback alone.
|
|
18
|
+
|
|
19
|
+
## Model and provider policy
|
|
20
|
+
|
|
21
|
+
The Hermes bridge does not choose a model/provider. When no session command is configured, GJC uses its normal local model/provider resolution. If the operator config supplies `GJC_COORDINATOR_MCP_SESSION_COMMAND`, preserve it as explicit user intent.
|
|
22
|
+
|
|
23
|
+
Provider-specific commands are examples only, never product defaults.
|
|
24
|
+
|
|
25
|
+
## Safety
|
|
26
|
+
|
|
27
|
+
- Mutating tools require bridge startup mutation classes and per-call consent.
|
|
28
|
+
- Allowed roots restrict workdir and artifact paths.
|
|
29
|
+
- Artifact reads are bounded and should be treated as evidence, not unlimited filesystem access.
|