Skip to content
Draft
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
2 changes: 2 additions & 0 deletions gui/src/components/codex-set/PromptLayerDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export default function PromptLayerDialog({
? t("codexSet.dialog.emptySource", { path: text.sourcePath ?? "" })
: text?.reason === "not-rendered"
? t("codexSet.dialog.notRendered")
: text?.reason === "unmapped"
? t("codexSet.dialog.unmapped")
: text?.reason === "not-exposed"
? t("codexSet.dialog.notExposed")
: t("codexSet.dialog.textUnavailable")}
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ export const de: Record<TKey, string> = {
"codexSet.dialog.notRendered": "In der gelesenen Runde hat diese Ebene nichts gesendet. Abschnitte werden nur bei Änderungen erneut gesendet, daher kann eine einzelne Stichprobe sie nicht enthalten.",
"codexSet.dialog.emptySource": "Die Datei unter {path} existiert, ist aber leer, daher sendet diese Ebene nichts.",
"codexSet.dialog.notExposed": "Der Basis-Prompt läuft außerhalb der Nachrichtenliste, die Codex ausgeben kann, und lässt sich hier nicht anzeigen. Ersetzen ist über model_instructions_file möglich.",
"codexSet.dialog.unmapped": "Für diese Ebene gibt es noch keine bestätigte Zuordnung in der Prompt-Ausgabe, daher kann ihr Text hier noch nicht angezeigt werden.",
"codexSet.dialog.textUnavailable": "Der Codex-Prompt konnte auf diesem Rechner nicht gelesen werden, daher ist der Text nicht verfügbar.",
"codexSet.class.base": "Basisanweisungen",
"codexSet.class.config-toggle": "Hier umschaltbar",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,7 @@ export const en = {
"codexSet.dialog.notRendered": "This layer sent nothing on the turn we read. Sections are only re-sent when they change, so an unchanged layer is absent from a single sample.",
"codexSet.dialog.emptySource": "The file at {path} exists but is empty, so this layer sends nothing.",
"codexSet.dialog.notExposed": "The base prompt travels outside the message list Codex can print, so it cannot be shown here. Replacing it is possible through model_instructions_file.",
"codexSet.dialog.unmapped": "This layer has no confirmed mapping in the prompt output, so its text cannot be shown here yet.",
"codexSet.dialog.textUnavailable": "The Codex prompt could not be read on this machine, so the text is unavailable.",
"codexSet.class.base": "Base instructions",
"codexSet.class.config-toggle": "Switchable here",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,7 @@ export const fr: Record<TKey, string> = {
"codexSet.dialog.notRendered": "Lors du tour que nous avons lu, cette couche n'a rien envoyé. Les sections ne sont renvoyées qu'en cas de changement : un seul échantillon peut donc ne pas la contenir.",
"codexSet.dialog.emptySource": "Le fichier {path} existe mais il est vide : cette couche n'envoie donc rien.",
"codexSet.dialog.notExposed": "L'invite de base circule en dehors de la liste de messages que Codex peut afficher ; elle ne peut donc pas être montrée ici. On peut la remplacer via model_instructions_file.",
"codexSet.dialog.unmapped": "Cette couche n'a pas encore de correspondance confirmée dans la sortie de l'invite ; son texte ne peut donc pas encore être affiché ici.",
"codexSet.dialog.textUnavailable": "L'invite Codex n'a pas pu être lue sur cette machine, le texte est donc indisponible.",
"codexSet.class.base": "Instructions de base",
"codexSet.class.config-toggle": "Modifiable ici",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,7 @@ export const ja: Record<TKey, string> = {
"codexSet.dialog.notRendered": "確認したターンでは、このレイヤーは何も送信していません。各セクションは内容が変わったときだけ再送されるため、一度の確認では欠けて見えることがあります。",
"codexSet.dialog.emptySource": "{path} のファイルは存在しますが空のため、このレイヤーは何も送信しません。",
"codexSet.dialog.notExposed": "基本プロンプトは Codex が出力するメッセージ一覧の外を通るため、ここには表示できません。model_instructions_file で置き換えることは可能です。",
"codexSet.dialog.unmapped": "このレイヤーにはプロンプト出力内で確認済みの対応付けがまだないため、ここにはテキストを表示できません。",
"codexSet.dialog.textUnavailable": "このマシンでは Codex のプロンプトを読み取れず、原文を表示できません。",
"codexSet.class.base": "基本指示",
"codexSet.class.config-toggle": "ここで切り替え可能",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,7 @@ export const ko: Record<TKey, string> = {
"codexSet.dialog.notRendered": "확인한 턴에서는 이 레이어가 아무것도 보내지 않았습니다. 각 섹션은 내용이 바뀔 때만 다시 전송되므로, 한 번 확인한 것만으로는 빠져 보일 수 있습니다.",
"codexSet.dialog.emptySource": "{path} 파일은 있지만 비어 있어서 이 레이어는 아무것도 보내지 않습니다.",
"codexSet.dialog.notExposed": "기본 프롬프트는 Codex가 출력하는 메시지 목록 밖으로 전달되어 여기서 보여줄 수 없습니다. 대신 model_instructions_file로 교체할 수 있습니다.",
"codexSet.dialog.unmapped": "이 레이어는 프롬프트 출력에서 확인된 매핑이 아직 없어 여기에서 텍스트를 표시할 수 없습니다.",
"codexSet.dialog.textUnavailable": "이 컴퓨터에서 Codex 프롬프트를 읽지 못해 원문을 표시할 수 없습니다.",
"codexSet.class.base": "기본 지침",
"codexSet.class.config-toggle": "여기서 전환 가능",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,7 @@ export const ru: Record<TKey, string> = {
"codexSet.dialog.notRendered": "На прочитанном нами шаге этот слой ничего не отправил. Разделы пересылаются только при изменении, поэтому в одной выборке слой может отсутствовать.",
"codexSet.dialog.emptySource": "Файл {path} существует, но пуст, поэтому этот слой ничего не отправляет.",
"codexSet.dialog.notExposed": "Базовый промпт передаётся вне списка сообщений, который Codex может напечатать, поэтому показать его здесь нельзя. Заменить его можно через model_instructions_file.",
"codexSet.dialog.unmapped": "Для этого слоя пока нет подтверждённого сопоставления в выводе промпта, поэтому его текст ещё нельзя показать здесь.",
"codexSet.dialog.textUnavailable": "На этой машине не удалось прочитать промпт Codex, поэтому текст недоступен.",
"codexSet.class.base": "Базовые инструкции",
"codexSet.class.config-toggle": "Переключается здесь",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,7 @@ export const tr: Record<TKey, string> = {
"codexSet.dialog.notRendered": "Okuduğumuz turda bu katman hiçbir şey göndermedi. Bölümler yalnızca değiştiklerinde yeniden gönderilir, bu yüzden tek bir örnekte görünmeyebilir.",
"codexSet.dialog.emptySource": "{path} konumundaki dosya var ancak boş, bu yüzden bu katman hiçbir şey göndermiyor.",
"codexSet.dialog.notExposed": "Temel istem, Codex'in yazdırabildiği mesaj listesinin dışından geçtiği için burada gösterilemez. model_instructions_file ile değiştirilebilir.",
"codexSet.dialog.unmapped": "Bu katmanın istem çıktısında henüz doğrulanmış bir eşlemesi yok, bu nedenle metni burada henüz gösterilemiyor.",
"codexSet.dialog.textUnavailable": "Bu makinede Codex istemi okunamadı, bu yüzden metin kullanılamıyor.",
"codexSet.class.base": "Temel talimatlar",
"codexSet.class.config-toggle": "Buradan değiştirilebilir",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,7 @@ export const zhTW: Record<TKey, string> = {
"codexSet.dialog.notRendered": "在我們讀取的那一輪中,此層沒有傳送任何內容。各區段只在內容變更時才會重新傳送,因此單次取樣可能看不到它。",
"codexSet.dialog.emptySource": "{path} 檔案存在但為空,因此此層不會傳送任何內容。",
"codexSet.dialog.notExposed": "基礎提示詞不在 Codex 可列印的訊息清單中傳遞,因此無法在此顯示。可以透過 model_instructions_file 取代它。",
"codexSet.dialog.unmapped": "此層在提示詞輸出中尚無已確認的對應,因此暫時無法在此顯示其文字。",
"codexSet.dialog.textUnavailable": "本機無法讀取 Codex 提示詞,因此無法顯示原文。",
"codexSet.class.base": "基礎指令",
"codexSet.class.config-toggle": "可在此切換",
Expand Down
1 change: 1 addition & 0 deletions gui/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,7 @@ export const zh: Record<TKey, string> = {
"codexSet.dialog.notRendered": "在我们读取的那一轮中,此层没有发送任何内容。各部分仅在内容变化时才会重新发送,因此单次采样可能看不到它。",
"codexSet.dialog.emptySource": "{path} 文件存在但为空,因此此层不会发送任何内容。",
"codexSet.dialog.notExposed": "基础提示词不在 Codex 可打印的消息列表中传递,因此无法在此显示。可以通过 model_instructions_file 替换它。",
"codexSet.dialog.unmapped": "此层在提示词输出中尚无已确认的映射,因此暂时无法在此显示其文本。",
"codexSet.dialog.textUnavailable": "本机无法读取 Codex 提示词,因此无法显示原文。",
"codexSet.class.base": "基础指令",
"codexSet.class.config-toggle": "可在此切换",
Expand Down
15 changes: 15 additions & 0 deletions gui/tests/codex-set-prompt-layers.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,21 @@ test("9. the dialog names WHY text is missing rather than omitting it silently",
await act(async () => { root.unmount(); });
});

test("9b. an unmapped layer does not receive the base-prompt explanation", async () => {
stubRoutes(call => call.url.endsWith("/api/codex-prompt/text")
? json({ ok: true, layers: { personality: { text: null, reason: "unmapped", bytes: 0 } } })
: json(snapshot()));
const { container, root } = await mount();
await act(async () => {
(row(container, "personality")!.querySelector("button") as HTMLButtonElement).click();
});
const notice = document.querySelector(".codex-set-layer-dialog__no-text")!;
expect(notice.textContent).toContain("no confirmed mapping");
expect(notice.textContent).not.toContain("base prompt");
expect(notice.textContent).not.toContain("model_instructions_file");
await act(async () => { root.unmount(); });
});

test("4. a runtime-conditional row states the condition that emits it", async () => {
stubRoutes(() => json(snapshot()));
const { container, root } = await mount();
Expand Down
7 changes: 4 additions & 3 deletions src/codex/prompt-text-probe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export interface LayerText {
/** Rendered text, when this layer produced a section on the probed turn. */
text: string | null;
/** Why the text is absent, when it is. */
reason: "ok" | "empty-source" | "not-rendered" | "not-exposed" | "unavailable";
reason: "ok" | "empty-source" | "not-rendered" | "not-exposed" | "unmapped" | "unavailable";
bytes: number;
/** For `empty-source`: the file that exists but has nothing in it. */
sourcePath?: string;
Expand Down Expand Up @@ -230,9 +230,10 @@ export async function probePromptText(timeoutMs = 15_000): Promise<PromptTextPro

// Layers whose rendered tag we have not confirmed against live output. Leaving
// them absent made the GUI fall through to "unavailable", which claims the probe
// failed when it succeeded. Saying we have no mapping is the smaller claim.
// failed when it succeeded. Keep this distinct from the base prompt, which is
// confirmed to travel outside the printable message list.
for (const id of UNMAPPED_LAYER_IDS) {
layers[id] ??= { text: null, reason: "not-exposed", bytes: 0 };
layers[id] ??= { text: null, reason: "unmapped", bytes: 0 };
}
return { ok: true, codexHome, layers };
}
5 changes: 5 additions & 0 deletions tests/codex-prompt-route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,11 @@ describe("020 coverage completions", () => {
// Decoding per chunk corrupts UTF-8 that straddles a chunk boundary.
expect(probe).toContain("Buffer.concat(chunks).toString(\"utf8\")");
});
test("27. unmapped layers stay distinct from the unprintable base prompt", async () => {
const probe = await Bun.file(new URL("../src/codex/prompt-text-probe.ts", import.meta.url)).text();
expect(probe).toContain('layers["base-instructions"] = { text: null, reason: "not-exposed"');
expect(probe).toContain('layers[id] ??= { text: null, reason: "unmapped"');
});
test("24. every ownership state is named, not collapsed into a boolean", async () => {
// developerInstructionsOwned:false covers an ABSENT key and an EXTERNAL one, and
// a GUI that cannot tell them apart hides its own create affordance from every
Expand Down
Loading