@gajae-code/coding-agent 0.1.2 → 0.2.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/CHANGELOG.md +30 -1
- package/dist/types/commands/gjc-runtime-bridge.d.ts +24 -0
- package/dist/types/config/model-registry.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +4 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +23 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +40 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +15 -10
- package/dist/types/hooks/skill-state.d.ts +4 -1
- package/dist/types/modes/components/model-selector.d.ts +2 -4
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -4
- package/dist/types/session/agent-session.d.ts +3 -9
- package/dist/types/skill-state/active-state.d.ts +19 -0
- package/dist/types/skill-state/workflow-hud.d.ts +62 -0
- package/package.json +9 -9
- package/src/commands/deep-interview.ts +21 -2
- package/src/commands/gjc-runtime-bridge.ts +161 -15
- package/src/commands/ralplan.ts +21 -2
- package/src/commands/team.ts +54 -3
- package/src/commands/ultragoal.ts +21 -1
- package/src/config/model-registry.ts +4 -0
- package/src/config/model-resolver.ts +5 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +6 -6
- package/src/defaults/gjc/skills/ralplan/SKILL.md +5 -9
- package/src/defaults/gjc/skills/team/SKILL.md +5 -4
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +8 -8
- package/src/gjc-runtime/launch-tmux.ts +73 -2
- package/src/gjc-runtime/team-runtime.ts +365 -35
- package/src/gjc-runtime/ultragoal-guard.ts +43 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +307 -187
- package/src/hooks/skill-state.ts +4 -1
- package/src/main.ts +1 -0
- package/src/modes/components/model-selector.ts +108 -8
- package/src/modes/components/skill-hud/render.ts +35 -8
- package/src/modes/interactive-mode.ts +34 -22
- package/src/prompts/system/system-prompt.md +5 -4
- package/src/sdk.ts +3 -1
- package/src/session/agent-session.ts +15 -3
- package/src/skill-state/active-state.ts +104 -4
- package/src/skill-state/workflow-hud.ts +160 -0
- package/src/tools/image-gen.ts +19 -10
|
@@ -7,6 +7,23 @@ export const SKILL_ACTIVE_STALE_MS = 24 * 60 * 60 * 1000;
|
|
|
7
7
|
export const CANONICAL_GJC_WORKFLOW_SKILLS = ["deep-interview", "ralplan", "ultragoal", "team"] as const;
|
|
8
8
|
|
|
9
9
|
export type CanonicalGjcWorkflowSkill = (typeof CANONICAL_GJC_WORKFLOW_SKILLS)[number];
|
|
10
|
+
export type WorkflowHudSeverity = "info" | "warning" | "blocked" | "error" | "success";
|
|
11
|
+
|
|
12
|
+
export interface WorkflowHudChip {
|
|
13
|
+
label: string;
|
|
14
|
+
value?: string;
|
|
15
|
+
priority?: number;
|
|
16
|
+
severity?: WorkflowHudSeverity;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface WorkflowHudSummary {
|
|
20
|
+
version: 1;
|
|
21
|
+
summary?: string;
|
|
22
|
+
chips?: WorkflowHudChip[];
|
|
23
|
+
details?: WorkflowHudChip[];
|
|
24
|
+
severity?: WorkflowHudSeverity;
|
|
25
|
+
updated_at?: string;
|
|
26
|
+
}
|
|
10
27
|
|
|
11
28
|
export interface SkillActiveEntry {
|
|
12
29
|
skill: string;
|
|
@@ -17,6 +34,8 @@ export interface SkillActiveEntry {
|
|
|
17
34
|
session_id?: string;
|
|
18
35
|
thread_id?: string;
|
|
19
36
|
turn_id?: string;
|
|
37
|
+
hud?: WorkflowHudSummary;
|
|
38
|
+
stale?: boolean;
|
|
20
39
|
}
|
|
21
40
|
|
|
22
41
|
export interface SkillActiveState {
|
|
@@ -50,12 +69,79 @@ export interface SyncSkillActiveStateOptions {
|
|
|
50
69
|
turnId?: string;
|
|
51
70
|
nowIso?: string;
|
|
52
71
|
source?: string;
|
|
72
|
+
hud?: WorkflowHudSummary;
|
|
53
73
|
}
|
|
54
74
|
|
|
75
|
+
const HUD_TEXT_LIMIT = 80;
|
|
76
|
+
const HUD_CHIP_LIMIT = 6;
|
|
77
|
+
const HUD_DETAIL_LIMIT = 12;
|
|
78
|
+
const ANSI_PATTERN = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
79
|
+
const HUD_SEVERITIES = new Set<WorkflowHudSeverity>(["info", "warning", "blocked", "error", "success"]);
|
|
80
|
+
|
|
55
81
|
function safeString(value: unknown): string {
|
|
56
82
|
return typeof value === "string" ? value : "";
|
|
57
83
|
}
|
|
58
84
|
|
|
85
|
+
function sanitizeHudString(value: unknown, limit = HUD_TEXT_LIMIT): string | undefined {
|
|
86
|
+
const normalized = safeString(value)
|
|
87
|
+
.replace(ANSI_PATTERN, "")
|
|
88
|
+
.replace(/[\r\n\t]+/g, " ")
|
|
89
|
+
.trim();
|
|
90
|
+
if (!normalized) return undefined;
|
|
91
|
+
return normalized.length > limit ? normalized.slice(0, limit) : normalized;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeSeverity(value: unknown): WorkflowHudSeverity | undefined {
|
|
95
|
+
return typeof value === "string" && HUD_SEVERITIES.has(value as WorkflowHudSeverity)
|
|
96
|
+
? (value as WorkflowHudSeverity)
|
|
97
|
+
: undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function normalizeHudChip(raw: unknown): WorkflowHudChip | null {
|
|
101
|
+
if (!raw || typeof raw !== "object") return null;
|
|
102
|
+
const record = raw as Record<string, unknown>;
|
|
103
|
+
const label = sanitizeHudString(record.label, 32);
|
|
104
|
+
if (!label) return null;
|
|
105
|
+
const value = sanitizeHudString(record.value, HUD_TEXT_LIMIT);
|
|
106
|
+
const priority =
|
|
107
|
+
typeof record.priority === "number" && Number.isFinite(record.priority) ? record.priority : undefined;
|
|
108
|
+
const severity = normalizeSeverity(record.severity);
|
|
109
|
+
return {
|
|
110
|
+
label,
|
|
111
|
+
...(value ? { value } : {}),
|
|
112
|
+
...(priority !== undefined ? { priority } : {}),
|
|
113
|
+
...(severity ? { severity } : {}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function normalizeHudChips(raw: unknown, limit: number): WorkflowHudChip[] | undefined {
|
|
118
|
+
if (!Array.isArray(raw)) return undefined;
|
|
119
|
+
const chips = raw
|
|
120
|
+
.map(normalizeHudChip)
|
|
121
|
+
.filter((chip): chip is WorkflowHudChip => chip !== null)
|
|
122
|
+
.slice(0, limit);
|
|
123
|
+
return chips.length > 0 ? chips : undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function normalizeWorkflowHudSummary(raw: unknown): WorkflowHudSummary | undefined {
|
|
127
|
+
if (!raw || typeof raw !== "object") return undefined;
|
|
128
|
+
const record = raw as Record<string, unknown>;
|
|
129
|
+
if (record.version !== 1) return undefined;
|
|
130
|
+
const summary = sanitizeHudString(record.summary);
|
|
131
|
+
const chips = normalizeHudChips(record.chips, HUD_CHIP_LIMIT);
|
|
132
|
+
const details = normalizeHudChips(record.details, HUD_DETAIL_LIMIT);
|
|
133
|
+
const severity = normalizeSeverity(record.severity);
|
|
134
|
+
const updatedAt = sanitizeHudString(record.updated_at, 40);
|
|
135
|
+
return {
|
|
136
|
+
version: 1,
|
|
137
|
+
...(summary ? { summary } : {}),
|
|
138
|
+
...(chips ? { chips } : {}),
|
|
139
|
+
...(details ? { details } : {}),
|
|
140
|
+
...(severity ? { severity } : {}),
|
|
141
|
+
...(updatedAt ? { updated_at: updatedAt } : {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
59
145
|
function encodePathSegment(value: string): string {
|
|
60
146
|
return encodeURIComponent(value).replaceAll(".", "%2E");
|
|
61
147
|
}
|
|
@@ -70,16 +156,25 @@ function timestampMs(value: string | undefined): number | null {
|
|
|
70
156
|
return Number.isFinite(ms) ? ms : null;
|
|
71
157
|
}
|
|
72
158
|
|
|
159
|
+
function entryTimestampMs(entry: SkillActiveEntry): number | null {
|
|
160
|
+
return timestampMs(entry.hud?.updated_at) ?? timestampMs(entry.updated_at) ?? timestampMs(entry.activated_at);
|
|
161
|
+
}
|
|
162
|
+
|
|
73
163
|
function isFreshEntry(entry: SkillActiveEntry, nowMs = Date.now()): boolean {
|
|
74
|
-
const ms =
|
|
164
|
+
const ms = entryTimestampMs(entry);
|
|
75
165
|
return ms === null || nowMs - ms <= SKILL_ACTIVE_STALE_MS;
|
|
76
166
|
}
|
|
77
167
|
|
|
168
|
+
function withDerivedStale(entry: SkillActiveEntry, nowMs = Date.now()): SkillActiveEntry {
|
|
169
|
+
return { ...entry, stale: !isFreshEntry(entry, nowMs) };
|
|
170
|
+
}
|
|
171
|
+
|
|
78
172
|
function normalizeEntry(raw: unknown): SkillActiveEntry | null {
|
|
79
173
|
if (!raw || typeof raw !== "object") return null;
|
|
80
174
|
const record = raw as Record<string, unknown>;
|
|
81
175
|
const skill = safeString(record.skill).trim();
|
|
82
176
|
if (!skill) return null;
|
|
177
|
+
const hud = normalizeWorkflowHudSummary(record.hud);
|
|
83
178
|
return {
|
|
84
179
|
...record,
|
|
85
180
|
skill,
|
|
@@ -90,6 +185,8 @@ function normalizeEntry(raw: unknown): SkillActiveEntry | null {
|
|
|
90
185
|
session_id: safeString(record.session_id).trim() || undefined,
|
|
91
186
|
thread_id: safeString(record.thread_id).trim() || undefined,
|
|
92
187
|
turn_id: safeString(record.turn_id).trim() || undefined,
|
|
188
|
+
...(hud ? { hud } : {}),
|
|
189
|
+
stale: undefined,
|
|
93
190
|
};
|
|
94
191
|
}
|
|
95
192
|
|
|
@@ -185,11 +282,12 @@ function mergeVisibleEntries(
|
|
|
185
282
|
rootState: SkillActiveState | null,
|
|
186
283
|
sessionId?: string,
|
|
187
284
|
): SkillActiveEntry[] {
|
|
188
|
-
const
|
|
189
|
-
|
|
285
|
+
const nowMs = Date.now();
|
|
286
|
+
const rootEntries = filterRootEntriesForSession(listActiveSkills(rootState), sessionId).map(entry =>
|
|
287
|
+
withDerivedStale(entry, nowMs),
|
|
190
288
|
);
|
|
191
289
|
const merged = new Map(rootEntries.map(entry => [entryKey(entry), entry]));
|
|
192
|
-
for (const entry of listActiveSkills(sessionState).
|
|
290
|
+
for (const entry of listActiveSkills(sessionState).map(candidate => withDerivedStale(candidate, nowMs))) {
|
|
193
291
|
merged.set(entryKey(entry), entry);
|
|
194
292
|
}
|
|
195
293
|
return [...merged.values()];
|
|
@@ -229,6 +327,7 @@ function upsertEntry(entries: SkillActiveEntry[], entry: SkillActiveEntry, activ
|
|
|
229
327
|
|
|
230
328
|
export async function syncSkillActiveState(options: SyncSkillActiveStateOptions): Promise<void> {
|
|
231
329
|
const nowIso = options.nowIso ?? new Date().toISOString();
|
|
330
|
+
const hud = normalizeWorkflowHudSummary(options.hud);
|
|
232
331
|
const entry: SkillActiveEntry = {
|
|
233
332
|
skill: options.skill,
|
|
234
333
|
phase: options.phase,
|
|
@@ -238,6 +337,7 @@ export async function syncSkillActiveState(options: SyncSkillActiveStateOptions)
|
|
|
238
337
|
session_id: options.sessionId,
|
|
239
338
|
thread_id: options.threadId,
|
|
240
339
|
turn_id: options.turnId,
|
|
340
|
+
...(hud ? { hud } : {}),
|
|
241
341
|
};
|
|
242
342
|
const { rootPath, sessionPath } = getSkillActiveStatePaths(options.cwd, options.sessionId);
|
|
243
343
|
const rootState = (await readStateFile(rootPath)) ?? { version: 1, active_skills: [] };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { WorkflowHudChip, WorkflowHudSummary } from "./active-state";
|
|
2
|
+
|
|
3
|
+
interface DeepInterviewHudState {
|
|
4
|
+
phase?: string;
|
|
5
|
+
ambiguity?: number;
|
|
6
|
+
threshold?: number;
|
|
7
|
+
roundCount?: number;
|
|
8
|
+
targetComponent?: string;
|
|
9
|
+
weakestDimension?: string;
|
|
10
|
+
specStatus?: string;
|
|
11
|
+
updatedAt?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface RalplanHudState {
|
|
15
|
+
stage?: string;
|
|
16
|
+
waiting?: string;
|
|
17
|
+
iteration?: number;
|
|
18
|
+
verdict?: string;
|
|
19
|
+
latestSummary?: string;
|
|
20
|
+
pendingApproval?: boolean;
|
|
21
|
+
updatedAt?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface UltragoalLikeGoal {
|
|
25
|
+
id: string;
|
|
26
|
+
title: string;
|
|
27
|
+
status: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface UltragoalHudState {
|
|
31
|
+
status: string;
|
|
32
|
+
currentGoal?: UltragoalLikeGoal;
|
|
33
|
+
counts: Record<string, number>;
|
|
34
|
+
goals: UltragoalLikeGoal[];
|
|
35
|
+
latestLedgerEvent?: { event?: string; goalId?: string; timestamp?: string };
|
|
36
|
+
updatedAt?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface TeamHudWorker {
|
|
40
|
+
id: string;
|
|
41
|
+
status?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface TeamHudState {
|
|
45
|
+
phase: string;
|
|
46
|
+
task_total: number;
|
|
47
|
+
task_counts: Record<string, number>;
|
|
48
|
+
workers: TeamHudWorker[];
|
|
49
|
+
updated_at?: string;
|
|
50
|
+
latestEvent?: { type?: string; worker?: string; message?: string };
|
|
51
|
+
latestMessage?: { from_worker?: string; body?: string };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function percent(value: number | undefined): string | undefined {
|
|
55
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
|
|
56
|
+
return `${Math.round(value * 100)}%`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function chip(
|
|
60
|
+
label: string,
|
|
61
|
+
value: string | undefined,
|
|
62
|
+
priority: number,
|
|
63
|
+
severity?: WorkflowHudChip["severity"],
|
|
64
|
+
): WorkflowHudChip | null {
|
|
65
|
+
if (!value) return null;
|
|
66
|
+
return { label, value, priority, ...(severity ? { severity } : {}) };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function compactChips(chips: Array<WorkflowHudChip | null>): WorkflowHudChip[] {
|
|
70
|
+
return chips.filter((item): item is WorkflowHudChip => item !== null);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function buildDeepInterviewHudSummary(state: DeepInterviewHudState): WorkflowHudSummary {
|
|
74
|
+
return {
|
|
75
|
+
version: 1,
|
|
76
|
+
chips: compactChips([
|
|
77
|
+
chip("phase", state.phase, 10),
|
|
78
|
+
chip("ambiguity", [percent(state.ambiguity), percent(state.threshold)].filter(Boolean).join("/"), 20),
|
|
79
|
+
chip("round", state.roundCount === undefined ? undefined : String(state.roundCount), 30),
|
|
80
|
+
chip("target", state.targetComponent, 40),
|
|
81
|
+
chip("weakest", state.weakestDimension, 50),
|
|
82
|
+
chip("spec", state.specStatus, 60),
|
|
83
|
+
]),
|
|
84
|
+
...(state.updatedAt ? { updated_at: state.updatedAt } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function buildRalplanHudSummary(state: RalplanHudState): WorkflowHudSummary {
|
|
89
|
+
const verdict = state.verdict?.toUpperCase();
|
|
90
|
+
const verdictSeverity =
|
|
91
|
+
verdict === "BLOCK"
|
|
92
|
+
? "blocked"
|
|
93
|
+
: verdict === "ITERATE" || verdict === "WATCH"
|
|
94
|
+
? "warning"
|
|
95
|
+
: verdict === "APPROVE" || verdict === "CLEAR"
|
|
96
|
+
? "success"
|
|
97
|
+
: undefined;
|
|
98
|
+
return {
|
|
99
|
+
version: 1,
|
|
100
|
+
summary: state.latestSummary,
|
|
101
|
+
chips: compactChips([
|
|
102
|
+
state.pendingApproval ? { label: "pending", value: "approval", priority: 5, severity: "warning" } : null,
|
|
103
|
+
chip("stage", state.stage, 10),
|
|
104
|
+
chip("waiting", state.waiting, 20),
|
|
105
|
+
chip("iter", state.iteration === undefined ? undefined : String(state.iteration), 30),
|
|
106
|
+
chip("verdict", verdict, 40, verdictSeverity),
|
|
107
|
+
]),
|
|
108
|
+
...(state.updatedAt ? { updated_at: state.updatedAt } : {}),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function buildUltragoalHudSummary(state: UltragoalHudState): WorkflowHudSummary {
|
|
113
|
+
const total = state.goals.length;
|
|
114
|
+
const complete = state.counts.complete ?? 0;
|
|
115
|
+
const blockers = (state.counts.blocked ?? 0) + (state.counts.review_blocked ?? 0) + (state.counts.failed ?? 0);
|
|
116
|
+
return {
|
|
117
|
+
version: 1,
|
|
118
|
+
chips: compactChips([
|
|
119
|
+
blockers > 0 ? { label: "blocked", value: String(blockers), priority: 5, severity: "blocked" } : null,
|
|
120
|
+
chip("goals", `${complete}/${total}`, 10),
|
|
121
|
+
chip("current", state.currentGoal ? `${state.currentGoal.id}:${state.currentGoal.title}` : state.status, 20),
|
|
122
|
+
chip("status", state.status, 30, state.status === "complete" ? "success" : undefined),
|
|
123
|
+
]),
|
|
124
|
+
details: state.latestLedgerEvent
|
|
125
|
+
? compactChips([
|
|
126
|
+
chip(
|
|
127
|
+
"ledger",
|
|
128
|
+
[state.latestLedgerEvent.event, state.latestLedgerEvent.goalId].filter(Boolean).join(":"),
|
|
129
|
+
100,
|
|
130
|
+
),
|
|
131
|
+
])
|
|
132
|
+
: undefined,
|
|
133
|
+
...(state.updatedAt ? { updated_at: state.updatedAt } : {}),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function buildTeamHudSummary(state: TeamHudState): WorkflowHudSummary {
|
|
138
|
+
const failedWorkers = state.workers.filter(
|
|
139
|
+
worker => worker.status === "failed" || worker.status === "blocked",
|
|
140
|
+
).length;
|
|
141
|
+
const stoppedWorkers = state.workers.filter(worker => worker.status === "stopped").length;
|
|
142
|
+
const completed = state.task_counts.completed ?? 0;
|
|
143
|
+
const failedTasks = (state.task_counts.failed ?? 0) + (state.task_counts.blocked ?? 0);
|
|
144
|
+
const latest = state.latestEvent?.message ?? state.latestEvent?.type ?? state.latestMessage?.body;
|
|
145
|
+
return {
|
|
146
|
+
version: 1,
|
|
147
|
+
chips: compactChips([
|
|
148
|
+
failedWorkers > 0 || failedTasks > 0
|
|
149
|
+
? { label: "blocked", value: String(failedWorkers + failedTasks), priority: 5, severity: "blocked" }
|
|
150
|
+
: stoppedWorkers > 0
|
|
151
|
+
? { label: "stopped", value: String(stoppedWorkers), priority: 5, severity: "warning" }
|
|
152
|
+
: null,
|
|
153
|
+
chip("phase", state.phase, 10),
|
|
154
|
+
chip("workers", `${state.workers.length - failedWorkers}/${state.workers.length}`, 20),
|
|
155
|
+
chip("tasks", `${completed}/${state.task_total}`, 30),
|
|
156
|
+
chip("latest", latest, 50),
|
|
157
|
+
]),
|
|
158
|
+
...(state.updated_at ? { updated_at: state.updated_at } : {}),
|
|
159
|
+
};
|
|
160
|
+
}
|
package/src/tools/image-gen.ts
CHANGED
|
@@ -44,6 +44,7 @@ interface ImageApiKey {
|
|
|
44
44
|
apiKey: string;
|
|
45
45
|
projectId?: string;
|
|
46
46
|
model?: Model;
|
|
47
|
+
authCredentialType?: "api_key" | "oauth";
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
const responseModalitySchema = z.enum(["IMAGE", "TEXT"] as const);
|
|
@@ -441,6 +442,7 @@ async function findOpenAIHostedImageCredentials(
|
|
|
441
442
|
provider: getOpenAIHostedImageProvider(activeModel),
|
|
442
443
|
apiKey,
|
|
443
444
|
model: activeModel,
|
|
445
|
+
authCredentialType: modelRegistry.getSessionCredentialType?.(activeModel.provider, sessionId),
|
|
444
446
|
};
|
|
445
447
|
}
|
|
446
448
|
|
|
@@ -700,16 +702,21 @@ function getOpenAIResponseErrorMessage(rawText: string): string {
|
|
|
700
702
|
}
|
|
701
703
|
}
|
|
702
704
|
|
|
703
|
-
function getOpenAIBaseUrl(model: Model): string {
|
|
704
|
-
|
|
705
|
-
model.
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
705
|
+
function getOpenAIBaseUrl(model: Model, authCredentialType?: "api_key" | "oauth"): string {
|
|
706
|
+
if (model.api === "openai-codex-responses" || model.provider === "openai-codex") {
|
|
707
|
+
return (model.baseUrl || CODEX_BASE_URL).replace(/\/+$/, "");
|
|
708
|
+
}
|
|
709
|
+
if (authCredentialType === "oauth") return DEFAULT_OPENAI_BASE_URL;
|
|
710
|
+
const envBaseUrl = $env.OPENAI_BASE_URL?.trim();
|
|
711
|
+
const configuredBaseUrl = model.baseUrl?.trim();
|
|
712
|
+
if (envBaseUrl && (!configuredBaseUrl || configuredBaseUrl.toLowerCase().includes("api.openai.com"))) {
|
|
713
|
+
return envBaseUrl.replace(/\/+$/, "");
|
|
714
|
+
}
|
|
715
|
+
return (configuredBaseUrl || envBaseUrl || DEFAULT_OPENAI_BASE_URL).replace(/\/+$/, "");
|
|
709
716
|
}
|
|
710
717
|
|
|
711
|
-
function getOpenAIResponsesUrl(model: Model): string {
|
|
712
|
-
const baseUrl = getOpenAIBaseUrl(model);
|
|
718
|
+
function getOpenAIResponsesUrl(model: Model, authCredentialType?: "api_key" | "oauth"): string {
|
|
719
|
+
const baseUrl = getOpenAIBaseUrl(model, authCredentialType);
|
|
713
720
|
if (model.api !== "openai-codex-responses" && model.provider !== "openai-codex") {
|
|
714
721
|
return `${baseUrl}/responses`;
|
|
715
722
|
}
|
|
@@ -782,11 +789,12 @@ async function generateOpenAIHostedImage(
|
|
|
782
789
|
inputImages: InlineImageData[],
|
|
783
790
|
signal: AbortSignal | undefined,
|
|
784
791
|
sessionId: string | undefined,
|
|
792
|
+
options?: { authCredentialType?: "api_key" | "oauth" },
|
|
785
793
|
): Promise<OpenAIHostedImageResult> {
|
|
786
794
|
const promptText = assemblePrompt(params);
|
|
787
795
|
const stream = model.api === "openai-codex-responses" || model.provider === "openai-codex";
|
|
788
796
|
const requestBody = buildOpenAIHostedImageRequest(model, promptText, params, inputImages, stream);
|
|
789
|
-
const response = await fetch(getOpenAIResponsesUrl(model), {
|
|
797
|
+
const response = await fetch(getOpenAIResponsesUrl(model, options?.authCredentialType), {
|
|
790
798
|
method: "POST",
|
|
791
799
|
headers: buildOpenAIImageHeaders(model, apiKey, sessionId),
|
|
792
800
|
body: JSON.stringify(requestBody),
|
|
@@ -946,6 +954,7 @@ export const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails
|
|
|
946
954
|
resolvedImages,
|
|
947
955
|
requestSignal,
|
|
948
956
|
sessionId,
|
|
957
|
+
{ authCredentialType: apiKey.authCredentialType },
|
|
949
958
|
);
|
|
950
959
|
|
|
951
960
|
if (parsed.images.length === 0) {
|
|
@@ -1075,7 +1084,7 @@ export const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails
|
|
|
1075
1084
|
headers: {
|
|
1076
1085
|
"Content-Type": "application/json",
|
|
1077
1086
|
Authorization: `Bearer ${apiKey.apiKey}`,
|
|
1078
|
-
"HTTP-Referer": "https://gajae
|
|
1087
|
+
"HTTP-Referer": "https://gaebal-gajae.dev/",
|
|
1079
1088
|
"X-OpenRouter-Title": "Gajae Code",
|
|
1080
1089
|
"X-OpenRouter-Categories": "cli-agent",
|
|
1081
1090
|
},
|