Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/grok/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,12 @@ export function findManagedRegion(content: string): ManagedRegion | null {
*/
const KEY_SEGMENT = String.raw`(?:[A-Za-z0-9_-]+|"(?:[^"\\]|\\.)*"|'[^']*')`;
/**
* User-owned model table headers. Also matches array-of-table (`[[model.x]]`) and sub-table
* (`[model.x.sub]`) spellings. `[[model.x]]` genuinely collides with a generated `[model.x]`,
* and one collision makes grok reject the ENTIRE config layer ("duplicate key"), taking every
* unrelated user setting with it; `[model.x.sub]` does not strictly collide, but reserving it
* costs only a suffixed alias and keeps us clear of the user's namespace.
*
* Every character class here is newline-free ON PURPOSE. With `[^\]]*` the optional sub-table
* tail runs past the end of its own line, so an unclosed `[model.…` inside a multiline string
* swallows the following lines — including a real `[model.<alias>]` header, which then goes
* unreserved and produces the very duplicate-key config this scan exists to prevent.
* User-owned model table headers. Also matches the array-of-table (`[[model.x]]`) spelling,
* which genuinely collides with a generated `[model.x]`. A sub-table (`[model.x.extra]`) does
* not collide: TOML permits its implicitly created parent to be defined explicitly later.
*/
const MODEL_TABLE_HEADER = new RegExp(
String.raw`^[ \t]*\[\[?[ \t]*(${KEY_SEGMENT})[ \t]*\.[ \t]*(${KEY_SEGMENT})[ \t]*(?:\.[^\]\r\n]*)?\]\]?[ \t]*(?:#.*)?$`,
String.raw`^[ \t]*\[\[?[ \t]*(${KEY_SEGMENT})[ \t]*\.[ \t]*(${KEY_SEGMENT})[ \t]*\]\]?[ \t]*(?:#.*)?$`,
Comment thread
luvs01 marked this conversation as resolved.
Comment thread
luvs01 marked this conversation as resolved.
"gm",
);

Expand Down
13 changes: 12 additions & 1 deletion tests/grok-config-inject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ describe("Grok config injection", () => {
["mixed quoting with whitespace", `[ "model" . 'ocx-mine' ]`],
["bare (baseline)", "[model.ocx-mine]"],
["array of tables", "[[model.ocx-mine]]"],
["sub-table", "[model.ocx-mine.extra]"],
["trailing comment", '[model."ocx-mine"] # mine'],
];

Expand All @@ -205,6 +204,18 @@ describe("Grok config injection", () => {
});
}

test("does not reserve an alias from a user sub-table", () => {
writeFileSync(configPath(), "[model.ocx-mine.extra]\nx = 1\n", "utf8");

injectGrokConfig(10100, [{ id: "mine" }], { grokHome });

const written = readFileSync(configPath(), "utf8");
const generated = written.slice(written.indexOf(BEGIN_MARKER));
expect(written).toContain("[model.ocx-mine.extra]");
expect(generated).toContain("[model.ocx-mine]\n");
expect(generated).not.toContain("[model.ocx-mine-2]");
});

test("does not reserve aliases from unrelated tables", () => {
// [models.*] and [model_providers.*] are different tables entirely — reserving from them
// would needlessly suffix our aliases.
Expand Down
Loading