@poncho-ai/harness 0.31.0 → 0.31.1

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.31.0 build /Users/cesar/Dev/latitude/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.31.1 build /Users/cesar/Dev/latitude/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,8 +8,8 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 314.45 KB
12
- ESM ⚡️ Build success in 89ms
11
+ ESM dist/index.js 315.41 KB
12
+ ESM ⚡️ Build success in 33ms
13
13
  DTS Build start
14
- DTS ⚡️ Build success in 4040ms
14
+ DTS ⚡️ Build success in 2913ms
15
15
  DTS dist/index.d.ts 32.56 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.31.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix OpenAI Codex compatibility for reasoning model runs by normalizing tool schemas, enforcing required payload fields, and adding endpoint fallback behavior.
8
+
3
9
  ## 0.31.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.js CHANGED
@@ -3887,6 +3887,7 @@ var MODEL_CONTEXT_WINDOWS = {
3887
3887
  };
3888
3888
  var DEFAULT_CONTEXT_WINDOW = 2e5;
3889
3889
  var OPENAI_CODEX_DEFAULT_INSTRUCTIONS = "You are Codex, based on GPT-5. You are running as a coding agent in Poncho.";
3890
+ var OPENAI_CODEX_RESPONSES_URL = process.env.OPENAI_CODEX_RESPONSES_URL ?? "https://chatgpt.com/backend-api/codex/responses";
3890
3891
  var extractSystemInstructionFromInput = (input) => {
3891
3892
  if (!Array.isArray(input)) return void 0;
3892
3893
  for (const message of input) {
@@ -3909,6 +3910,18 @@ var extractSystemInstructionFromInput = (input) => {
3909
3910
  }
3910
3911
  return void 0;
3911
3912
  };
3913
+ var normalizeToolParameterSchemas = (tools) => {
3914
+ if (!Array.isArray(tools)) return;
3915
+ for (const tool of tools) {
3916
+ if (!tool || typeof tool !== "object") continue;
3917
+ const entry = tool;
3918
+ if (!entry.parameters || typeof entry.parameters !== "object") continue;
3919
+ const schema = entry.parameters;
3920
+ if (schema.type === "object" && (typeof schema.properties !== "object" || schema.properties === null)) {
3921
+ schema.properties = {};
3922
+ }
3923
+ }
3924
+ };
3912
3925
  var getModelContextWindow = (modelName) => {
3913
3926
  if (MODEL_CONTEXT_WINDOWS[modelName] !== void 0) {
3914
3927
  return MODEL_CONTEXT_WINDOWS[modelName];
@@ -3938,7 +3951,7 @@ var createModelProvider = (provider, config) => {
3938
3951
  const originalUrl = input instanceof URL ? input.toString() : typeof input === "string" ? input : input.url;
3939
3952
  const parsed = new URL(originalUrl);
3940
3953
  const shouldRewrite = parsed.pathname.includes("/v1/responses") || parsed.pathname.includes("/chat/completions");
3941
- const targetUrl = shouldRewrite ? "https://chatgpt.com/backend-api/codex/responses" : originalUrl;
3954
+ const targetUrl = shouldRewrite ? OPENAI_CODEX_RESPONSES_URL : originalUrl;
3942
3955
  let body = init?.body;
3943
3956
  if (shouldRewrite && typeof body === "string" && headers.get("Content-Type")?.includes("application/json")) {
3944
3957
  try {
@@ -3946,12 +3959,21 @@ var createModelProvider = (provider, config) => {
3946
3959
  if (typeof payload.instructions !== "string" || payload.instructions.trim() === "") {
3947
3960
  payload.instructions = extractSystemInstructionFromInput(payload.input) ?? OPENAI_CODEX_DEFAULT_INSTRUCTIONS;
3948
3961
  }
3962
+ normalizeToolParameterSchemas(payload.tools);
3949
3963
  payload.store = false;
3950
3964
  body = JSON.stringify(payload);
3951
3965
  } catch {
3952
3966
  }
3953
3967
  }
3954
- return fetch(targetUrl, { ...init, headers, body });
3968
+ try {
3969
+ return await fetch(targetUrl, { ...init, headers, body });
3970
+ } catch (error) {
3971
+ const message = error instanceof Error ? error.message : String(error);
3972
+ if (shouldRewrite && targetUrl.includes("chatgpt.com") && message.includes("ENOTFOUND chatgpt.com")) {
3973
+ return fetch(originalUrl, { ...init, headers, body });
3974
+ }
3975
+ throw error;
3976
+ }
3955
3977
  }
3956
3978
  });
3957
3979
  return (modelName) => openai(modelName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.31.0",
3
+ "version": "0.31.1",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,6 +36,8 @@ const MODEL_CONTEXT_WINDOWS: Record<string, number> = {
36
36
  const DEFAULT_CONTEXT_WINDOW = 200_000;
37
37
  const OPENAI_CODEX_DEFAULT_INSTRUCTIONS =
38
38
  "You are Codex, based on GPT-5. You are running as a coding agent in Poncho.";
39
+ const OPENAI_CODEX_RESPONSES_URL =
40
+ process.env.OPENAI_CODEX_RESPONSES_URL ?? "https://chatgpt.com/backend-api/codex/responses";
39
41
 
40
42
  const extractSystemInstructionFromInput = (input: unknown): string | undefined => {
41
43
  if (!Array.isArray(input)) return undefined;
@@ -62,6 +64,22 @@ const extractSystemInstructionFromInput = (input: unknown): string | undefined =
62
64
  return undefined;
63
65
  };
64
66
 
67
+ const normalizeToolParameterSchemas = (tools: unknown): void => {
68
+ if (!Array.isArray(tools)) return;
69
+ for (const tool of tools) {
70
+ if (!tool || typeof tool !== "object") continue;
71
+ const entry = tool as { parameters?: unknown };
72
+ if (!entry.parameters || typeof entry.parameters !== "object") continue;
73
+ const schema = entry.parameters as {
74
+ type?: unknown;
75
+ properties?: unknown;
76
+ };
77
+ if (schema.type === "object" && (typeof schema.properties !== "object" || schema.properties === null)) {
78
+ schema.properties = {};
79
+ }
80
+ }
81
+ };
82
+
65
83
  /**
66
84
  * Returns the context window size (in tokens) for a given model name.
67
85
  * Uses startsWith matching so dated variants (e.g. claude-opus-4-6-20260217)
@@ -117,7 +135,7 @@ export const createModelProvider = (provider?: string, config?: ProviderConfig):
117
135
  parsed.pathname.includes("/v1/responses") ||
118
136
  parsed.pathname.includes("/chat/completions");
119
137
  const targetUrl = shouldRewrite
120
- ? "https://chatgpt.com/backend-api/codex/responses"
138
+ ? OPENAI_CODEX_RESPONSES_URL
121
139
  : originalUrl;
122
140
  let body = init?.body;
123
141
  if (
@@ -130,12 +148,14 @@ export const createModelProvider = (provider?: string, config?: ProviderConfig):
130
148
  instructions?: unknown;
131
149
  input?: unknown;
132
150
  store?: unknown;
151
+ tools?: unknown;
133
152
  };
134
153
  if (typeof payload.instructions !== "string" || payload.instructions.trim() === "") {
135
154
  payload.instructions =
136
155
  extractSystemInstructionFromInput(payload.input) ??
137
156
  OPENAI_CODEX_DEFAULT_INSTRUCTIONS;
138
157
  }
158
+ normalizeToolParameterSchemas(payload.tools);
139
159
  // Codex endpoint requires store=false explicitly.
140
160
  payload.store = false;
141
161
  body = JSON.stringify(payload);
@@ -143,7 +163,20 @@ export const createModelProvider = (provider?: string, config?: ProviderConfig):
143
163
  // Keep original body if parsing fails.
144
164
  }
145
165
  }
146
- return fetch(targetUrl, { ...init, headers, body });
166
+ try {
167
+ return await fetch(targetUrl, { ...init, headers, body });
168
+ } catch (error) {
169
+ const message = error instanceof Error ? error.message : String(error);
170
+ if (
171
+ shouldRewrite &&
172
+ targetUrl.includes("chatgpt.com") &&
173
+ message.includes("ENOTFOUND chatgpt.com")
174
+ ) {
175
+ // Some networks block/override chatgpt.com DNS; retry on the SDK's original URL.
176
+ return fetch(originalUrl, { ...init, headers, body });
177
+ }
178
+ throw error;
179
+ }
147
180
  },
148
181
  });
149
182
  return (modelName: string) => openai(modelName);