@gaia-ai/addon-grok 0.11.5 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.d.ts +12 -3
- package/dist/src/index.js +99 -3
- package/dist/src/preset.d.ts +2 -1
- package/dist/src/preset.js +13 -5
- package/package.json +3 -3
package/dist/src/index.d.ts
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import type { AgentFootprint, AgentPlugin, GaiaAgent } from '@gaia-ai/conductor/contract';
|
|
1
|
+
import type { AgentFootprint, AgentPlugin, AgentRunIdentity, GaiaAgent } from '@gaia-ai/conductor/contract';
|
|
2
2
|
export { parseGrokTranscript } from './footprint.js';
|
|
3
3
|
export type GrokReasoningEffort = 'high' | 'medium' | 'low';
|
|
4
4
|
export interface GrokAgentOptions {
|
|
5
5
|
model: string;
|
|
6
6
|
reasoningEffort?: GrokReasoningEffort;
|
|
7
7
|
}
|
|
8
|
+
export declare const DEFAULT_GROK_MODEL = "grok-4.6";
|
|
8
9
|
export declare function encodeGrokSessionCwd(cwd: string): string;
|
|
9
10
|
export declare class GrokAgent implements GaiaAgent {
|
|
10
11
|
private readonly options;
|
|
11
12
|
private readonly home;
|
|
12
13
|
readonly id = "grok";
|
|
13
14
|
constructor(options?: GrokAgentOptions, home?: string);
|
|
14
|
-
launchCommand(prompt: string): string;
|
|
15
|
-
|
|
15
|
+
launchCommand(prompt: string, run?: AgentRunIdentity): string;
|
|
16
|
+
/**
|
|
17
|
+
* `grok --session-id <uuid>` documents "new conversation… must not already
|
|
18
|
+
* exist" (GAIA-473 review round 2), so the conductor checks this before
|
|
19
|
+
* pinning the run's own UUID — a re-dispatch of the same run would
|
|
20
|
+
* otherwise mint the id its first attempt already wrote and fail to
|
|
21
|
+
* launch.
|
|
22
|
+
*/
|
|
23
|
+
sessionExists(worktreePath: string, sessionId: string): Promise<boolean>;
|
|
24
|
+
getRunLog(worktreePath: string, run?: AgentRunIdentity): Promise<string>;
|
|
16
25
|
parseFootprint(log: string): AgentFootprint;
|
|
17
26
|
}
|
|
18
27
|
export declare function grokAgent(options?: GrokAgentOptions): AgentPlugin;
|
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,8 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { shellQuote } from '@gaia-ai/core';
|
|
5
5
|
import { parseGrokTranscript } from './footprint.js';
|
|
6
6
|
export { parseGrokTranscript } from './footprint.js';
|
|
7
|
-
const
|
|
7
|
+
export const DEFAULT_GROK_MODEL = 'grok-4.6';
|
|
8
|
+
const DEFAULT_OPTIONS = { model: DEFAULT_GROK_MODEL };
|
|
8
9
|
export function encodeGrokSessionCwd(cwd) {
|
|
9
10
|
return encodeURIComponent(cwd);
|
|
10
11
|
}
|
|
@@ -35,7 +36,7 @@ export class GrokAgent {
|
|
|
35
36
|
this.options = options;
|
|
36
37
|
this.home = home;
|
|
37
38
|
}
|
|
38
|
-
launchCommand(prompt) {
|
|
39
|
+
launchCommand(prompt, run) {
|
|
39
40
|
const parts = ['grok'];
|
|
40
41
|
if (prompt !== '') {
|
|
41
42
|
// Positional — the interactive form Grok Build documents
|
|
@@ -48,10 +49,100 @@ export class GrokAgent {
|
|
|
48
49
|
if (this.options.reasoningEffort) {
|
|
49
50
|
parts.push('--reasoning-effort', this.options.reasoningEffort);
|
|
50
51
|
}
|
|
52
|
+
// Pin the session dir name to the run's UUID (GAIA-473), so `getRunLog`
|
|
53
|
+
// can select it directly instead of scanning every session dir under the
|
|
54
|
+
// cwd for the newest match — the scan is what let a foreign transcript
|
|
55
|
+
// (resumed run, re-dispatch, reused worktree) get finalised.
|
|
56
|
+
if (run?.sessionId) {
|
|
57
|
+
parts.push('--session-id', run.sessionId);
|
|
58
|
+
}
|
|
51
59
|
return parts.join(' ');
|
|
52
60
|
}
|
|
53
|
-
|
|
61
|
+
/**
|
|
62
|
+
* `grok --session-id <uuid>` documents "new conversation… must not already
|
|
63
|
+
* exist" (GAIA-473 review round 2), so the conductor checks this before
|
|
64
|
+
* pinning the run's own UUID — a re-dispatch of the same run would
|
|
65
|
+
* otherwise mint the id its first attempt already wrote and fail to
|
|
66
|
+
* launch.
|
|
67
|
+
*/
|
|
68
|
+
async sessionExists(worktreePath, sessionId) {
|
|
69
|
+
const dir = join(this.home, '.grok', 'sessions', encodeGrokSessionCwd(worktreePath), sessionId);
|
|
70
|
+
return (await readJson(join(dir, 'summary.json'))) !== null;
|
|
71
|
+
}
|
|
72
|
+
async getRunLog(worktreePath, run) {
|
|
54
73
|
const root = join(this.home, '.grok', 'sessions', encodeGrokSessionCwd(worktreePath));
|
|
74
|
+
const startedAtMs = run?.startedAt !== undefined ? new Date(run.startedAt).getTime() : null;
|
|
75
|
+
// GAIA-473: when the run's own session id is known (pinned at launch via
|
|
76
|
+
// `--session-id`), read that session dir directly — no directory scan,
|
|
77
|
+
// so a foreign transcript can never be selected. AC-5: when the pinned
|
|
78
|
+
// session dir is missing (a run dispatched before this change, or the
|
|
79
|
+
// agent never wrote it), fall through to the scan below — bounded by
|
|
80
|
+
// `run.startedAt` where known — instead of returning '' and turning a
|
|
81
|
+
// wrong log into no log at all.
|
|
82
|
+
//
|
|
83
|
+
// Round 4 (review round 3, Critical 1): the pinned dir can also be
|
|
84
|
+
// *stale* — a re-dispatch omits `--session-id` (see `sessionExists`)
|
|
85
|
+
// because attempt 1's dir already owns this name, so a direct read here
|
|
86
|
+
// would silently keep returning attempt 1's transcript. `startedAt` is
|
|
87
|
+
// re-stamped on every dispatch, so a pinned dir older than this
|
|
88
|
+
// attempt's own start can only be a prior attempt's leftover — reject it
|
|
89
|
+
// and fall through to the scan, bounded by the same timestamp.
|
|
90
|
+
// GAIA-473 review round 4 (Critical 2): prefer the deterministic attempt
|
|
91
|
+
// family — the HIGHEST-numbered attempt whose session dir actually
|
|
92
|
+
// exists — over the `startedAt` window below, which a sibling session
|
|
93
|
+
// newer than the bound could still beat. Each family member names a
|
|
94
|
+
// distinct attempt, so no staleness check is needed.
|
|
95
|
+
if (run?.attemptFamily?.length) {
|
|
96
|
+
for (let i = run.attemptFamily.length - 1; i >= 0; i--) {
|
|
97
|
+
const candidate = run.attemptFamily[i];
|
|
98
|
+
if (!candidate)
|
|
99
|
+
continue;
|
|
100
|
+
const dir = join(root, candidate);
|
|
101
|
+
const summary = await readJson(join(dir, 'summary.json'));
|
|
102
|
+
if (!summary) {
|
|
103
|
+
continue; // try the next, lower-numbered attempt.
|
|
104
|
+
}
|
|
105
|
+
const [signals, chatHistory, updates] = await Promise.all([
|
|
106
|
+
readJson(join(dir, 'signals.json')),
|
|
107
|
+
readText(join(dir, 'chat_history.jsonl')),
|
|
108
|
+
readText(join(dir, 'updates.jsonl')),
|
|
109
|
+
]);
|
|
110
|
+
return JSON.stringify({
|
|
111
|
+
summary,
|
|
112
|
+
signals: signals ?? {},
|
|
113
|
+
chatHistory,
|
|
114
|
+
updates,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// AC-5: none of the family's dirs exist yet — fall through to the scan.
|
|
118
|
+
}
|
|
119
|
+
else if (run?.sessionId) {
|
|
120
|
+
const dir = join(root, run.sessionId);
|
|
121
|
+
const summary = await readJson(join(dir, 'summary.json'));
|
|
122
|
+
let isStale = false;
|
|
123
|
+
if (summary && startedAtMs !== null && Number.isFinite(startedAtMs)) {
|
|
124
|
+
try {
|
|
125
|
+
isStale = (await stat(dir)).mtimeMs < startedAtMs;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
isStale = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (summary && !isStale) {
|
|
132
|
+
const [signals, chatHistory, updates] = await Promise.all([
|
|
133
|
+
readJson(join(dir, 'signals.json')),
|
|
134
|
+
readText(join(dir, 'chat_history.jsonl')),
|
|
135
|
+
readText(join(dir, 'updates.jsonl')),
|
|
136
|
+
]);
|
|
137
|
+
return JSON.stringify({
|
|
138
|
+
summary,
|
|
139
|
+
signals: signals ?? {},
|
|
140
|
+
chatHistory,
|
|
141
|
+
updates,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// fall through to the scan.
|
|
145
|
+
}
|
|
55
146
|
let names;
|
|
56
147
|
try {
|
|
57
148
|
names = await readdir(root);
|
|
@@ -83,6 +174,11 @@ export class GrokAgent {
|
|
|
83
174
|
continue;
|
|
84
175
|
}
|
|
85
176
|
}
|
|
177
|
+
if (startedAtMs !== null &&
|
|
178
|
+
Number.isFinite(startedAtMs) &&
|
|
179
|
+
updated < startedAtMs) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
86
182
|
if (!latest || updated > latest.updated) {
|
|
87
183
|
latest = { dir, summary, updated };
|
|
88
184
|
}
|
package/dist/src/preset.d.ts
CHANGED
package/dist/src/preset.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import grokAgent from './index.js';
|
|
2
|
-
export const agents = (acc, opts) =>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import grokAgent, { DEFAULT_GROK_MODEL, } from './index.js';
|
|
2
|
+
export const agents = (acc, opts) => {
|
|
3
|
+
const model = opts?.model ?? DEFAULT_GROK_MODEL;
|
|
4
|
+
return [
|
|
5
|
+
...acc,
|
|
6
|
+
{
|
|
7
|
+
alias: 'grok',
|
|
8
|
+
description: 'Reasoning and implementation through Grok Build.',
|
|
9
|
+
model,
|
|
10
|
+
agent: grokAgent({ ...opts, model }),
|
|
11
|
+
},
|
|
12
|
+
];
|
|
13
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaia-ai/addon-grok",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "GAIA agent plugin for xAI Grok Build, with a real session footprint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"directory": "gaia-cli/addons/grok"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@gaia-ai/conductor": "^0.
|
|
24
|
-
"@gaia-ai/core": "^0.
|
|
23
|
+
"@gaia-ai/conductor": "^0.13.0",
|
|
24
|
+
"@gaia-ai/core": "^0.13.0"
|
|
25
25
|
}
|
|
26
26
|
}
|