@gajae-code/coding-agent 0.4.1 → 0.4.3
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 +22 -0
- package/dist/types/async/job-manager.d.ts +25 -0
- package/dist/types/commands/ultragoal.d.ts +1 -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 +26 -4
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +8 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +29 -0
- package/dist/types/harness-control-plane/finalize.d.ts +8 -0
- package/dist/types/harness-control-plane/receipts.d.ts +16 -1
- package/dist/types/harness-control-plane/types.d.ts +16 -3
- 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/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/reminders/star-reminder.d.ts +115 -0
- package/dist/types/session/agent-session.d.ts +30 -1
- package/dist/types/session/session-manager.d.ts +1 -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/examples/extensions/README.md +20 -41
- package/package.json +7 -7
- package/src/async/job-manager.ts +120 -1
- package/src/cli/grep-cli.ts +1 -1
- package/src/commands/harness.ts +42 -3
- package/src/commands/ultragoal.ts +8 -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 +27 -4
- package/src/defaults/gjc/skills/team/SKILL.md +10 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +3 -2
- package/src/gjc-runtime/goal-mode-request.ts +21 -1
- package/src/gjc-runtime/launch-tmux.ts +25 -2
- package/src/gjc-runtime/team-runtime.ts +78 -3
- package/src/gjc-runtime/ultragoal-guard.ts +18 -2
- package/src/gjc-runtime/ultragoal-runtime.ts +240 -30
- package/src/harness-control-plane/finalize.ts +84 -0
- package/src/harness-control-plane/owner.ts +16 -3
- package/src/harness-control-plane/receipts.ts +39 -1
- package/src/harness-control-plane/rpc-adapter.ts +7 -1
- package/src/harness-control-plane/types.ts +33 -12
- package/src/internal-urls/docs-index.generated.ts +3 -3
- 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/controllers/input-controller.ts +27 -7
- package/src/modes/controllers/selector-controller.ts +7 -1
- package/src/modes/interactive-mode.ts +29 -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/explore.md +1 -1
- package/src/prompts/agents/plan.md +1 -1
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/tools/browser.md +3 -2
- package/src/reminders/star-reminder.ts +422 -0
- package/src/runtime-mcp/manager.ts +15 -2
- package/src/sdk.ts +3 -1
- package/src/session/agent-session.ts +139 -17
- package/src/session/session-manager.ts +1 -1
- package/src/task/agents.ts +1 -1
- 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/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
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical AgentSession event observation: the single semantic mapping from
|
|
3
|
+
* `AgentSessionEvent` (and non-event wire frames) to bounded owner observations.
|
|
4
|
+
*
|
|
5
|
+
* This is the one place that derives `AgentWireOwnerObservation`s. Harness (and
|
|
6
|
+
* any other owner control plane) consumes these instead of re-parsing the wire
|
|
7
|
+
* protocol with private knowledge.
|
|
8
|
+
*
|
|
9
|
+
* Hard rule: evidence is BOUNDED — only ids, names, categories, statuses,
|
|
10
|
+
* cursors, timestamps, and short codes/messages. Never assistant text, message
|
|
11
|
+
* deltas, command output, raw args, or raw tool results.
|
|
12
|
+
*/
|
|
13
|
+
import type { AgentSessionEvent } from "../../../session/agent-session";
|
|
14
|
+
import type { AgentWireEventPayload, AgentWireOwnerObservation } from "./event-contract";
|
|
15
|
+
import { toAgentWireEventPayload } from "./event-envelope";
|
|
16
|
+
|
|
17
|
+
const TEST_RE = /\b(bun test|npm test|yarn test|pnpm test|jest|vitest|pytest|go test|cargo test|mocha|ava)\b/i;
|
|
18
|
+
const TOOL_STATUS_CODES = new Set([
|
|
19
|
+
"aborted",
|
|
20
|
+
"blocked",
|
|
21
|
+
"cancelled",
|
|
22
|
+
"complete",
|
|
23
|
+
"completed",
|
|
24
|
+
"error",
|
|
25
|
+
"failed",
|
|
26
|
+
"ok",
|
|
27
|
+
"pending",
|
|
28
|
+
"running",
|
|
29
|
+
"skipped",
|
|
30
|
+
"success",
|
|
31
|
+
"timeout",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
/** True when a tool name or command indicates a test-runner invocation. */
|
|
35
|
+
export function isTestRunnerTool(toolName?: unknown, command?: unknown): boolean {
|
|
36
|
+
const name = typeof toolName === "string" ? toolName : "";
|
|
37
|
+
const cmd = typeof command === "string" ? command : "";
|
|
38
|
+
if (/test/i.test(name) && name !== "edit" && name !== "read") return true;
|
|
39
|
+
return TEST_RE.test(cmd);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function str(v: unknown): string | undefined {
|
|
43
|
+
return typeof v === "string" ? v : undefined;
|
|
44
|
+
}
|
|
45
|
+
function num(v: unknown): number | undefined {
|
|
46
|
+
return typeof v === "number" ? v : undefined;
|
|
47
|
+
}
|
|
48
|
+
/** Only accept a known closed-vocabulary tool status; reject arbitrary strings. */
|
|
49
|
+
export function boundedStatus(v: unknown): string | undefined {
|
|
50
|
+
if (typeof v !== "string") return undefined;
|
|
51
|
+
const status = v.trim().toLowerCase();
|
|
52
|
+
return TOOL_STATUS_CODES.has(status) ? status : undefined;
|
|
53
|
+
}
|
|
54
|
+
/** Accept only identifier-shaped tokens (e.g. RPC command names); reject free text. */
|
|
55
|
+
export function boundedToken(v: unknown): string | undefined {
|
|
56
|
+
if (typeof v !== "string") return undefined;
|
|
57
|
+
return /^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(v) ? v : undefined;
|
|
58
|
+
}
|
|
59
|
+
function recordObject(v: unknown): Record<string, unknown> | undefined {
|
|
60
|
+
return v && typeof v === "object" && !Array.isArray(v) ? (v as Record<string, unknown>) : undefined;
|
|
61
|
+
}
|
|
62
|
+
function idOf(v: unknown): string | null {
|
|
63
|
+
const record = recordObject(v);
|
|
64
|
+
return str(record?.id) ?? null;
|
|
65
|
+
}
|
|
66
|
+
/** Extract a bounded tool command for test detection only — never persisted. */
|
|
67
|
+
function toolCommand(args: unknown): string | undefined {
|
|
68
|
+
const record = recordObject(args);
|
|
69
|
+
const c = record?.command ?? record?.cmd ?? record?.commandLine;
|
|
70
|
+
return typeof c === "string" ? c : undefined;
|
|
71
|
+
}
|
|
72
|
+
/** Derive a bounded tool status from a result/partialResult/isError shape. */
|
|
73
|
+
function resultStatus(result: unknown, isError?: boolean): string | undefined {
|
|
74
|
+
if (isError === true) return "error";
|
|
75
|
+
const record = recordObject(result);
|
|
76
|
+
if (!record) return undefined;
|
|
77
|
+
if (record.isError === true) return "error";
|
|
78
|
+
return boundedStatus(record.status) ?? boundedStatus(recordObject(record.details)?.status);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function obs(
|
|
82
|
+
event: AgentSessionEvent,
|
|
83
|
+
partial: Omit<AgentWireOwnerObservation, "eventType">,
|
|
84
|
+
): AgentWireOwnerObservation {
|
|
85
|
+
return { eventType: event.type, ...partial };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Map a single `AgentSessionEvent` to its bounded owner observation, or null
|
|
90
|
+
* when the event carries no owner-facing signal.
|
|
91
|
+
*/
|
|
92
|
+
export function observeAgentSessionEvent(event: AgentSessionEvent): AgentWireOwnerObservation | null {
|
|
93
|
+
switch (event.type) {
|
|
94
|
+
case "agent_start":
|
|
95
|
+
return obs(event, {
|
|
96
|
+
kind: "rpc_agent_started",
|
|
97
|
+
signal: "SessionStart",
|
|
98
|
+
evidence: {},
|
|
99
|
+
severity: "info",
|
|
100
|
+
semantic: true,
|
|
101
|
+
coalesceKey: null,
|
|
102
|
+
});
|
|
103
|
+
case "turn_start":
|
|
104
|
+
return obs(event, {
|
|
105
|
+
kind: "rpc_turn_started",
|
|
106
|
+
signal: "prompt-accepted",
|
|
107
|
+
evidence: {},
|
|
108
|
+
severity: "info",
|
|
109
|
+
semantic: true,
|
|
110
|
+
coalesceKey: null,
|
|
111
|
+
});
|
|
112
|
+
case "turn_end":
|
|
113
|
+
return obs(event, {
|
|
114
|
+
kind: "rpc_turn_ended",
|
|
115
|
+
signal: null,
|
|
116
|
+
evidence: {},
|
|
117
|
+
severity: "info",
|
|
118
|
+
semantic: false,
|
|
119
|
+
coalesceKey: null,
|
|
120
|
+
});
|
|
121
|
+
case "message_start":
|
|
122
|
+
case "message_update":
|
|
123
|
+
case "message_end": {
|
|
124
|
+
const messageId = idOf(event.message);
|
|
125
|
+
return obs(event, {
|
|
126
|
+
kind: "rpc_message_activity",
|
|
127
|
+
signal: null,
|
|
128
|
+
evidence: { phase: event.type, messageId },
|
|
129
|
+
severity: "info",
|
|
130
|
+
semantic: false,
|
|
131
|
+
coalesceKey: `message:${messageId ?? "msg"}`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
case "tool_execution_start": {
|
|
135
|
+
const test = isTestRunnerTool(event.toolName, toolCommand(event.args));
|
|
136
|
+
return obs(event, {
|
|
137
|
+
kind: "rpc_tool_started",
|
|
138
|
+
signal: test ? "test-running" : "tool-call",
|
|
139
|
+
evidence: { toolId: str(event.toolCallId) ?? null, toolName: str(event.toolName) ?? null },
|
|
140
|
+
severity: "info",
|
|
141
|
+
semantic: true,
|
|
142
|
+
coalesceKey: null,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
case "tool_execution_update": {
|
|
146
|
+
const test = isTestRunnerTool(event.toolName, toolCommand(event.args));
|
|
147
|
+
return obs(event, {
|
|
148
|
+
kind: "rpc_tool_updated",
|
|
149
|
+
signal: test ? "test-running" : null,
|
|
150
|
+
evidence: { toolId: str(event.toolCallId) ?? null, status: resultStatus(event.partialResult) ?? null },
|
|
151
|
+
severity: "info",
|
|
152
|
+
semantic: false,
|
|
153
|
+
coalesceKey: `tool:${str(event.toolCallId) ?? "tool"}`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
case "tool_execution_end": {
|
|
157
|
+
const test = isTestRunnerTool(event.toolName);
|
|
158
|
+
const status = resultStatus(event.result, event.isError);
|
|
159
|
+
return obs(event, {
|
|
160
|
+
kind: "rpc_tool_ended",
|
|
161
|
+
signal: test ? "test-running" : "tool-call",
|
|
162
|
+
evidence: {
|
|
163
|
+
toolId: str(event.toolCallId) ?? null,
|
|
164
|
+
toolName: str(event.toolName) ?? null,
|
|
165
|
+
status: status ?? null,
|
|
166
|
+
},
|
|
167
|
+
severity: status === "error" ? "warn" : "info",
|
|
168
|
+
semantic: true,
|
|
169
|
+
coalesceKey: null,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
case "auto_compaction_start":
|
|
173
|
+
case "auto_compaction_end":
|
|
174
|
+
return obs(event, {
|
|
175
|
+
kind: "rpc_compaction",
|
|
176
|
+
signal: null,
|
|
177
|
+
evidence: { phase: event.type },
|
|
178
|
+
severity: "info",
|
|
179
|
+
semantic: false,
|
|
180
|
+
coalesceKey: null,
|
|
181
|
+
});
|
|
182
|
+
case "auto_retry_start":
|
|
183
|
+
return obs(event, {
|
|
184
|
+
kind: "rpc_retry",
|
|
185
|
+
signal: null,
|
|
186
|
+
evidence: { phase: event.type, attempt: num(event.attempt) ?? null },
|
|
187
|
+
severity: "warn",
|
|
188
|
+
semantic: false,
|
|
189
|
+
coalesceKey: null,
|
|
190
|
+
});
|
|
191
|
+
case "auto_retry_end":
|
|
192
|
+
return obs(event, {
|
|
193
|
+
kind: "rpc_retry",
|
|
194
|
+
signal: null,
|
|
195
|
+
evidence: { phase: event.type, success: event.success === true },
|
|
196
|
+
severity: "warn",
|
|
197
|
+
semantic: false,
|
|
198
|
+
coalesceKey: null,
|
|
199
|
+
});
|
|
200
|
+
case "retry_fallback_applied":
|
|
201
|
+
case "retry_fallback_succeeded":
|
|
202
|
+
return obs(event, {
|
|
203
|
+
kind: "rpc_retry_fallback",
|
|
204
|
+
signal: null,
|
|
205
|
+
evidence: { phase: event.type, role: str(event.role) ?? null },
|
|
206
|
+
severity: "warn",
|
|
207
|
+
semantic: false,
|
|
208
|
+
coalesceKey: null,
|
|
209
|
+
});
|
|
210
|
+
case "ttsr_triggered":
|
|
211
|
+
return obs(event, {
|
|
212
|
+
kind: "rpc_ttsr",
|
|
213
|
+
signal: "error",
|
|
214
|
+
evidence: { ruleCount: Array.isArray(event.rules) ? event.rules.length : 0 },
|
|
215
|
+
severity: "warn",
|
|
216
|
+
semantic: true,
|
|
217
|
+
coalesceKey: null,
|
|
218
|
+
});
|
|
219
|
+
case "todo_reminder":
|
|
220
|
+
case "todo_auto_clear":
|
|
221
|
+
return obs(event, {
|
|
222
|
+
kind: "rpc_todo",
|
|
223
|
+
signal: null,
|
|
224
|
+
evidence: { phase: event.type },
|
|
225
|
+
severity: "info",
|
|
226
|
+
semantic: false,
|
|
227
|
+
coalesceKey: null,
|
|
228
|
+
});
|
|
229
|
+
case "irc_message":
|
|
230
|
+
return obs(event, {
|
|
231
|
+
kind: "rpc_irc",
|
|
232
|
+
signal: null,
|
|
233
|
+
evidence: {},
|
|
234
|
+
severity: "info",
|
|
235
|
+
semantic: false,
|
|
236
|
+
coalesceKey: null,
|
|
237
|
+
});
|
|
238
|
+
case "notice": {
|
|
239
|
+
const level = event.level;
|
|
240
|
+
return obs(event, {
|
|
241
|
+
kind: "rpc_notice",
|
|
242
|
+
signal: level === "error" ? "error" : null,
|
|
243
|
+
evidence: { level },
|
|
244
|
+
severity: level === "info" ? "info" : "warn",
|
|
245
|
+
semantic: level === "error",
|
|
246
|
+
coalesceKey: null,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
case "thinking_level_changed":
|
|
250
|
+
return obs(event, {
|
|
251
|
+
kind: "rpc_thinking",
|
|
252
|
+
signal: null,
|
|
253
|
+
evidence: { thinkingLevel: str(event.thinkingLevel) ?? null },
|
|
254
|
+
severity: "info",
|
|
255
|
+
semantic: false,
|
|
256
|
+
coalesceKey: null,
|
|
257
|
+
});
|
|
258
|
+
case "goal_updated":
|
|
259
|
+
return obs(event, {
|
|
260
|
+
kind: "rpc_goal",
|
|
261
|
+
signal: null,
|
|
262
|
+
evidence: { hasGoal: event.goal != null },
|
|
263
|
+
severity: "info",
|
|
264
|
+
semantic: false,
|
|
265
|
+
coalesceKey: null,
|
|
266
|
+
});
|
|
267
|
+
case "agent_end":
|
|
268
|
+
return obs(event, {
|
|
269
|
+
kind: "rpc_agent_completed",
|
|
270
|
+
signal: "completed",
|
|
271
|
+
evidence: { stopReason: str(event.stopReason) ?? "completed" },
|
|
272
|
+
severity: "info",
|
|
273
|
+
semantic: true,
|
|
274
|
+
coalesceKey: null,
|
|
275
|
+
});
|
|
276
|
+
default:
|
|
277
|
+
return assertNeverEvent(event);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function assertNeverEvent(event: never): null {
|
|
282
|
+
void (event as AgentSessionEvent);
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Build the rich event payload (renderer-facing) for an `AgentSessionEvent`. */
|
|
287
|
+
export { toAgentWireEventPayload };
|
|
288
|
+
|
|
289
|
+
/** Observe the bounded owner signal carried by a rich event payload. */
|
|
290
|
+
export function observeAgentWireEventPayload(payload: AgentWireEventPayload): AgentWireOwnerObservation | null {
|
|
291
|
+
return observeAgentSessionEvent(payload.event);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function ownerFrame(
|
|
295
|
+
frameType: string,
|
|
296
|
+
partial: Omit<AgentWireOwnerObservation, "frameType">,
|
|
297
|
+
): AgentWireOwnerObservation {
|
|
298
|
+
return { frameType, ...partial };
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Map a single outbound RPC wire frame (docs/rpc.md) to a bounded owner
|
|
303
|
+
* observation, or null when the frame carries no owner-facing signal. Event
|
|
304
|
+
* frames delegate to {@link observeAgentWireEventPayload}; non-event frames are
|
|
305
|
+
* mapped here so owners never re-parse protocol semantics privately.
|
|
306
|
+
*/
|
|
307
|
+
export function observeRpcOutboundFrame(frame: Record<string, unknown>): AgentWireOwnerObservation | null {
|
|
308
|
+
const type = str(frame.type);
|
|
309
|
+
if (!type || type === "ready") return null;
|
|
310
|
+
|
|
311
|
+
switch (type) {
|
|
312
|
+
case "response": {
|
|
313
|
+
if (frame.success === false) {
|
|
314
|
+
const error = recordObject(frame.error);
|
|
315
|
+
return ownerFrame(type, {
|
|
316
|
+
kind: "rpc_response_failed",
|
|
317
|
+
signal: "error",
|
|
318
|
+
evidence: {
|
|
319
|
+
command: boundedToken(frame.command) ?? null,
|
|
320
|
+
id: boundedToken(frame.id) ?? null,
|
|
321
|
+
code: boundedToken(error?.code) ?? null,
|
|
322
|
+
},
|
|
323
|
+
severity: "warn",
|
|
324
|
+
semantic: false,
|
|
325
|
+
coalesceKey: null,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
case "event": {
|
|
331
|
+
const payload = recordObject(frame.payload);
|
|
332
|
+
const event = recordObject(payload?.event);
|
|
333
|
+
if (!event) return null;
|
|
334
|
+
return observeAgentSessionEvent(event as unknown as AgentSessionEvent);
|
|
335
|
+
}
|
|
336
|
+
case "workflow_gate":
|
|
337
|
+
return ownerFrame(type, {
|
|
338
|
+
kind: "rpc_workflow_gate",
|
|
339
|
+
signal: null,
|
|
340
|
+
evidence: {
|
|
341
|
+
gate_id: str(frame.gate_id) ?? null,
|
|
342
|
+
kind: str(frame.kind) ?? null,
|
|
343
|
+
stage: str(frame.stage) ?? null,
|
|
344
|
+
},
|
|
345
|
+
severity: "info",
|
|
346
|
+
semantic: true,
|
|
347
|
+
coalesceKey: null,
|
|
348
|
+
});
|
|
349
|
+
case "extension_ui_request":
|
|
350
|
+
return ownerFrame(type, {
|
|
351
|
+
kind: "rpc_extension_request",
|
|
352
|
+
signal: "tool-call",
|
|
353
|
+
evidence: { id: str(frame.id) ?? null, method: str(frame.method) ?? null },
|
|
354
|
+
severity: "info",
|
|
355
|
+
semantic: false,
|
|
356
|
+
coalesceKey: null,
|
|
357
|
+
});
|
|
358
|
+
case "extension_error":
|
|
359
|
+
return ownerFrame(type, {
|
|
360
|
+
kind: "rpc_extension_error",
|
|
361
|
+
signal: "error",
|
|
362
|
+
evidence: {
|
|
363
|
+
extensionPath: str(frame.extensionPath) ?? null,
|
|
364
|
+
event: boundedToken(frame.event) ?? null,
|
|
365
|
+
},
|
|
366
|
+
severity: "critical",
|
|
367
|
+
semantic: true,
|
|
368
|
+
coalesceKey: null,
|
|
369
|
+
});
|
|
370
|
+
case "host_tool_call":
|
|
371
|
+
case "host_tool_cancel":
|
|
372
|
+
return ownerFrame(type, {
|
|
373
|
+
kind: type === "host_tool_cancel" ? "rpc_host_tool_cancel" : "rpc_host_tool_call",
|
|
374
|
+
signal: "tool-call",
|
|
375
|
+
evidence: { id: str(frame.id) ?? null, toolName: str(frame.toolName) ?? null },
|
|
376
|
+
severity: "info",
|
|
377
|
+
semantic: false,
|
|
378
|
+
coalesceKey: null,
|
|
379
|
+
});
|
|
380
|
+
case "host_uri_request":
|
|
381
|
+
case "host_uri_cancel":
|
|
382
|
+
return ownerFrame(type, {
|
|
383
|
+
kind: type === "host_uri_cancel" ? "rpc_host_uri_cancel" : "rpc_host_uri_request",
|
|
384
|
+
signal: "tool-call",
|
|
385
|
+
evidence: {
|
|
386
|
+
id: str(frame.id) ?? null,
|
|
387
|
+
operation: str(frame.operation) ?? null,
|
|
388
|
+
scheme: str(frame.scheme) ?? null,
|
|
389
|
+
},
|
|
390
|
+
severity: "info",
|
|
391
|
+
semantic: false,
|
|
392
|
+
coalesceKey: null,
|
|
393
|
+
});
|
|
394
|
+
default:
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
@@ -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));
|
|
@@ -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
|
---
|
|
@@ -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.
|