modify template
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf of
|
||||
any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don\'t include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,167 @@
|
||||
---
|
||||
name: "openai-docs"
|
||||
description: "Use when the user asks how to build with OpenAI products or APIs, asks about Codex itself or choosing Codex surfaces, needs up-to-date official documentation with citations, help choosing the latest model for a use case, or model upgrade and prompt-upgrade guidance; use OpenAI docs MCP tools for non-Codex docs questions, use the Codex manual helper first for broad Codex self-knowledge, and restrict fallback browsing to official OpenAI domains."
|
||||
---
|
||||
|
||||
|
||||
# OpenAI Docs
|
||||
|
||||
Provide authoritative, current guidance from OpenAI developer docs using the developers.openai.com MCP server. "Docs MCP" means `mcp__openaiDeveloperDocs__search_openai_docs` and `mcp__openaiDeveloperDocs__fetch_openai_doc`; for API reference, schema, parameter, or required-field questions, also use `mcp__openaiDeveloperDocs__get_openapi_spec` when available. Official-domain web search is fallback after those tools are unavailable or unhelpful. Broad Codex questions use the manual helper before Docs MCP. This skill also owns model selection, API model migration, and prompt-upgrade guidance.
|
||||
|
||||
## API Key Setup
|
||||
|
||||
For requests to build, run, configure, debug, or implement an API-backed app, script, CLI, generator, or tool, use `openai-platform-api-key` first when available. After that credential gate is resolved, return here for current docs as needed.
|
||||
|
||||
Use this skill directly for docs-only questions, citations, model/API guidance, conceptual explanations, and examples that do not require building or running an API-backed artifact.
|
||||
|
||||
## Workflow Configuration
|
||||
|
||||
### Source Priority
|
||||
|
||||
- For Codex self-knowledge, use the Codex source route below; it owns when to use the manual helper, Docs MCP, or bounded uncertainty.
|
||||
- For non-Codex OpenAI docs questions, use `mcp__openaiDeveloperDocs__search_openai_docs` to find the most relevant doc pages.
|
||||
- For non-Codex OpenAI docs questions, fetch the relevant page with `mcp__openaiDeveloperDocs__fetch_openai_doc` before answering. If search is noisy, run a narrower Docs MCP search; when any plausible official OpenAI docs URL is known or found, try fetching that URL through Docs MCP before relying on web-search content.
|
||||
- For API reference, schema, parameter, or required-field questions, use `mcp__openaiDeveloperDocs__get_openapi_spec` when available to verify the API shape alongside the relevant guide or reference page.
|
||||
- Use `mcp__openaiDeveloperDocs__list_openai_docs` only when you need to browse or discover non-Codex pages without a clear query.
|
||||
- For model-selection, "latest model", or default-model questions, fetch `https://developers.openai.com/api/docs/guides/latest-model.md` first. If that is unavailable, load `references/latest-model.md`.
|
||||
- For model upgrades or prompt upgrades, run `node scripts/resolve-latest-model-info.js` only when the target is latest/current/default or otherwise unspecified; otherwise preserve the explicitly requested target.
|
||||
- Preserve explicit target requests: if the user names a target model like "migrate to GPT-5.4", keep that requested target even if `latest-model.md` names a newer model. Mention newer guidance only as optional.
|
||||
- If current remote guidance is needed, fetch both the returned migration and prompting guide URLs directly. If direct fetch fails, use MCP/search fallback; if that also fails, use bundled fallback references and disclose the fallback.
|
||||
|
||||
## OpenAI product snapshots
|
||||
|
||||
1. Apps SDK: Build ChatGPT apps by providing a web component UI and an MCP server that exposes your app's tools to ChatGPT.
|
||||
2. Responses API: A unified endpoint designed for stateful, multimodal, tool-using interactions in agentic workflows.
|
||||
3. Chat Completions API: Generate a model response from a list of messages comprising a conversation.
|
||||
4. Codex: OpenAI's coding agent for software development that can write, understand, review, and debug code.
|
||||
5. gpt-oss: Open-weight OpenAI reasoning models (gpt-oss-120b and gpt-oss-20b) released under the Apache 2.0 license.
|
||||
6. Realtime API: Build low-latency, multimodal experiences including natural speech-to-speech conversations.
|
||||
7. Agents SDK: A toolkit for building agentic apps where a model can use tools and context, hand off to other agents, stream partial results, and keep a full trace.
|
||||
|
||||
## Codex self-knowledge
|
||||
|
||||
Use this path for questions about Codex itself: configuring, extending, operating, troubleshooting, local state, product surfaces, or where Codex behavior should live. A codebase merely mentioning a plugin, skill, hook, MCP server, browser, or automation is not enough. For generic software tasks, answer the software task directly; if asked whether Codex self-knowledge applies, answer that meta question briefly and continue the requested artifact.
|
||||
|
||||
### Source Route
|
||||
|
||||
The Codex manual is the first source for broad Codex synthesis. Treat the manual and Docs MCP as different lanes, not interchangeable official-doc sources. For published-user Codex product answers, the source route is complete: the manual, Docs MCP when this route calls for it, official OpenAI web fallback, and callable capabilities surfaced in the current session when the question is about that capability. Knowledge bases outside developers.openai.com are outside this route for public product answers.
|
||||
|
||||
For broad Codex behavior, setup, customization, skills, plugins, MCP, hooks, `AGENTS.md`, automations, surfaces, local state, or system-map questions:
|
||||
|
||||
1. Reuse a same-thread manual and outline path when it is still fresh.
|
||||
2. Otherwise run the skill-local helper first in normal writable sessions. Skip it without trying only when the session is explicitly read-only, shell execution is unavailable, or visible policy shows no allowed temp cache.
|
||||
3. By default, the helper chooses the first usable temp cache dir in this order: `$TMPDIR/openai-docs-cache`, `%TEMP%\openai-docs-cache`, `%TMP%\openai-docs-cache`, `/private/tmp/openai-docs-cache`, then `/tmp/openai-docs-cache`. Workspace-only write access is not enough for this temp cache.
|
||||
4. Run the helper directly unless you need to override the cache dir. The helper falls back to `curl` when native `fetch` is unavailable or when proxy env vars are present, so no shell-specific proxy prefix is required. Resolve `<skill-dir>` to this skill's actual directory; in copied local eval workdirs this is usually `.codex/skills/openai-docs`:
|
||||
|
||||
```bash
|
||||
node <skill-dir>/scripts/fetch-codex-manual.mjs
|
||||
```
|
||||
|
||||
If you need to override the cache dir, pass `--cache-dir <cache-dir>`. On Windows, the helper checks `%TEMP%` and `%TMP%` automatically; in PowerShell, `$env:TEMP\\openai-docs-cache` is a typical explicit override.
|
||||
|
||||
Treat helper availability as established by explicit read-only/no-shell policy or an actual command result. A guessed sandbox or guessed helper failure is not enough to switch to Docs MCP or web lookup; after an actual helper command failure, continue to the narrowest official next source below.
|
||||
|
||||
The helper verifies freshness, writes `codex-manual.md`, and emits `codex-manual.outline.md`. The outline maps source pages and headings to line ranges; use it to choose the relevant manual section, then read or search targeted manual sections for Codex product facts. Use the skill directory to locate and run the helper; after the helper succeeds, use the returned manual and outline paths as the search scope for Codex product facts and term coverage checks.
|
||||
|
||||
Reuse the same-thread manual and outline paths for follow-up Codex questions. Refresh first when the manual was fetched more than about a day ago, the path is unusable, the path came from another thread or uncertain provenance, or likely-current information is missing and staleness is plausible.
|
||||
|
||||
For questions about whether the manual is current enough to rely on now, run the helper when temp caching is allowed and base the answer on its returned status, manual path, and outline path.
|
||||
|
||||
If the manual resolves a Codex claim, answer from it and stop expanding sources for that claim; continue the user's broader task if the docs lookup was only one dependency. Manual source pages and known anchors are enough citation support for manual-covered material.
|
||||
|
||||
If the helper is skipped because the session is read-only, has no shell execution, or has no allowed temp cache, the next source is Docs MCP: call `mcp__openaiDeveloperDocs__search_openai_docs`, then `mcp__openaiDeveloperDocs__fetch_openai_doc` for a relevant hit before any web fallback.
|
||||
|
||||
If a user names a Codex term or mode that a fresh manual does not use, search the manual for obvious adjacent concepts, then answer that the exact term is not documented and use the closest documented terminology. If the prompt asks how that term maps to Codex behavior, resolve the mapping from adjacent manual sections. If the exact term remains material or likely current after that manual pass, use one narrow Docs MCP search/fetch before bounded uncertainty; otherwise, the source lookup for that terminology or mapping claim is complete.
|
||||
|
||||
Use the narrowest official next source only when the manual is unavailable, the helper fails, temp caching is not allowed, another material claim is missing or likely stale, or the user explicitly needs a page-specific citation. Prefer one specific Docs MCP search and, if it returns a clearly relevant page, one fetch; for unresolved Codex capability names, acronyms, scheduling terms, or exact error text, this Docs MCP step is the next source before web search. After the manual plus any permitted Docs MCP gap-fill, resolve remaining gaps as bounded uncertainty. Use official-domain web fallback only after that Docs MCP path is unavailable or unhelpful. If the claim is still not established, stop with bounded uncertainty. If official docs/manual conflict with a callable capability already surfaced in the current session, state the conflict and prefer verified current-session behavior for that environment.
|
||||
|
||||
For undocumented or private-looking model slugs, product mode labels, entitlement labels, account access paths, or rollout names, answer from current public docs and bounded uncertainty. Those labels are not a reason to leave the public source route.
|
||||
|
||||
For support-style diagnostics, prefer a layer-by-layer answer from the manual over provider-specific web lookups: installed/enabled plugin, bundled app or connector authorization, MCP setup, workspace/admin policy, restart or new-thread expectations, then support or feedback if still unresolved.
|
||||
|
||||
If the source route still does not establish a claim, return bounded uncertainty or route to support, an admin, or product feedback instead of widening the investigation.
|
||||
|
||||
For unresolved product terminology, answer from the manual plus the allowed official next source. If those sources do not establish the term, answer with bounded uncertainty from those sources.
|
||||
|
||||
### Surface Map
|
||||
|
||||
When Codex nouns or durable-instruction surfaces overlap, recommend the smallest surface that matches the scope:
|
||||
|
||||
- Prompt or thread context -> one-off task constraints.
|
||||
- `AGENTS.md` -> durable repo conventions, commands, verification steps, and review expectations; closer nested files apply under their subtree.
|
||||
- Project `.codex/config.toml` -> trusted-repo Codex settings such as sandbox, MCP, hooks, model, or reasoning defaults.
|
||||
- Global config or global guidance -> personal defaults across repos.
|
||||
- Skill -> reusable task workflow with references or scripts.
|
||||
- Plugin -> installable bundle with skills plus commands, tools, MCP config, hooks, assets, apps, or marketplace metadata.
|
||||
- MCP server or app connector -> live external data/actions or authorized private app/workspace data. Use connectors for private Google Docs, Calendar, Slack, GitHub, Notion, and similar data instead of web search or model memory.
|
||||
- Automation -> scheduled checks, reminders, monitors, or follow-up work; use a thread heartbeat when continuity in an existing thread matters.
|
||||
- Hook -> lifecycle enforcement around tool calls, commands, or file edits.
|
||||
|
||||
Split mixed-scope requests instead of forcing one answer. Example: "always do X, but only for this PR" defaults to prompt/thread context for the current run; use `AGENTS.md` or project config only if it should persist, hooks only for mechanical enforcement, and automations only for scheduled or follow-up work.
|
||||
|
||||
Use this quick product map when needed: CLI is terminal-first local repo work; IDE extension is editor-attached coding; Codex app is desktop planning, review, and interactive work; cloud/web is hosted parallel/offloaded work; Browser Use/in-app browser is Codex-controlled web testing; Chrome extension uses the user's Chrome profile; Computer Use controls desktop apps and OS UI. Keep `config.toml` defaults, `requirements.toml` constraints, and managed/admin policy separate.
|
||||
|
||||
### Boundaries And Output
|
||||
|
||||
- API key auth does not imply ChatGPT, cloud task, or connector access. For plugin/app/auth failures, check bundle availability, plugin installed/enabled state, connector/app authorization, MCP setup, restart/refresh expectations, workspace policy, and per-surface availability before answering.
|
||||
- Sandbox or network denials need scoped escalation with a clear justification. Destructive commands, writes outside the workspace, or broad access changes require explicit approval.
|
||||
- Memory can provide user preference or context, but explicit prompt instructions win and memory is not a source for current external facts.
|
||||
- For affirmative surface-selection answers, use this shape: recommendation, why, what to avoid, and the manual/source evidence used.
|
||||
- When page-specific Codex citations are actually needed, these anchors often fit: `concepts/customization#agents-guidance` for `AGENTS.md`, `concepts/customization#skills` for skills, `plugins/build#plugin-structure` for plugins, `concepts/customization#mcp` for MCP, `config-advanced#hooks` for hooks, `app/automations#thread-automations` for thread automations, and `config-reference#configtoml` for config.
|
||||
|
||||
## If MCP server is missing
|
||||
|
||||
If MCP tools fail or no OpenAI docs resources are available:
|
||||
|
||||
1. Run the install command yourself: `codex mcp add openaiDeveloperDocs --url https://developers.openai.com/mcp`
|
||||
2. If it fails due to permissions/sandboxing, immediately retry the same command with escalated permissions and include a 1-sentence justification for approval.
|
||||
3. Ask the user to run the install command only if the escalated attempt fails.
|
||||
4. Ask the user to restart Codex.
|
||||
5. Re-run the doc search/fetch after restart.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Clarify whether the request is general docs lookup, model selection, a model-string upgrade, prompt-upgrade guidance, or broader API/provider migration.
|
||||
2. For Codex self-knowledge requests, follow the Codex self-knowledge source procedure above.
|
||||
3. For model-selection or upgrade requests, prefer current remote docs over bundled references when the user asks for latest/current/default guidance.
|
||||
- Fetch `https://developers.openai.com/api/docs/guides/latest-model.md`.
|
||||
- Find the latest model ID and explicit migration or prompt-guidance links.
|
||||
- Prefer explicit links from the latest-model page over derived URLs.
|
||||
- For explicit named-model requests, preserve the requested model target. Mention newer remote guidance only as optional.
|
||||
- For dynamic latest/current/default upgrades, run `node scripts/resolve-latest-model-info.js`, then fetch both returned guide URLs directly when possible.
|
||||
- If direct guide fetch fails, use the developer-docs MCP tools or official OpenAI-domain search to find the same guide content.
|
||||
- If remote docs are unavailable, use bundled fallback references and say that fallback guidance was used.
|
||||
4. For model upgrades, keep changes narrow: update active OpenAI API model defaults and directly related prompts only when safe.
|
||||
5. Leave historical docs, examples, eval baselines, fixtures, provider comparisons, provider registries, pricing tables, alias defaults, low-cost fallback paths, and ambiguous older model usage unchanged unless the user explicitly asks to upgrade them.
|
||||
6. Keep SDK, tooling, IDE, plugin, shell, auth, and provider-environment migrations out of a model-and-prompt upgrade unless the user explicitly asks for them.
|
||||
7. If an upgrade needs API-surface changes, schema rewiring, tool-handler changes, or implementation work beyond a literal model-string replacement and prompt edits, report it as blocked or confirmation-needed.
|
||||
8. For general docs lookup, search docs with a precise query, fetch the best page and exact section needed, and answer with concise citations.
|
||||
|
||||
## Reference map
|
||||
|
||||
Read only what you need:
|
||||
|
||||
- `https://developers.openai.com/api/docs/guides/latest-model.md` -> current model-selection and "best/latest/current model" questions.
|
||||
- `scripts/fetch-codex-manual.mjs` -> current Codex manual fetch, verification, local temp cache, and outline generation.
|
||||
- `https://developers.openai.com/codex/codex-manual.md` -> current Codex self-knowledge synthesis, including setup, customization, skills, plugins, MCP, hooks, `AGENTS.md`, automations, and surface behavior; normally access it through the helper path and targeted file reads when temp caching is available.
|
||||
- `references/latest-model.md` -> bundled fallback for model-selection and "best/latest/current model" questions.
|
||||
- `references/upgrade-guide.md` -> bundled fallback for model upgrade and upgrade-planning requests.
|
||||
- `references/prompting-guide.md` -> bundled fallback for prompt rewrites and prompt-behavior upgrades.
|
||||
|
||||
## Quality rules
|
||||
|
||||
- Treat OpenAI docs as the source of truth; avoid speculation.
|
||||
- For Codex self-knowledge, follow the source route above instead of relying on remembered behavior.
|
||||
- Keep migration changes narrow and behavior-preserving.
|
||||
- Prefer prompt-only upgrades when possible.
|
||||
- Avoid inventing pricing, availability, parameters, API changes, or breaking changes.
|
||||
- Keep quotes short and within policy limits; prefer paraphrase with citations.
|
||||
- If multiple pages differ, call out the difference and cite both.
|
||||
- If official docs and verified callable current-session behavior disagree, state the conflict before making broad claims or edits.
|
||||
- If docs do not cover the user’s need, say so and offer next steps.
|
||||
|
||||
## Tooling notes
|
||||
|
||||
- Use MCP doc tools before web search for OpenAI-related markdown docs. The Codex manual flow is the exception: follow the Codex self-knowledge source procedure for broad Codex synthesis.
|
||||
- If the MCP server is installed but returns no meaningful results, then use web search as a fallback.
|
||||
- When falling back to web search, restrict to official OpenAI domains (developers.openai.com, platform.openai.com) and cite sources.
|
||||
@@ -0,0 +1,14 @@
|
||||
interface:
|
||||
display_name: "OpenAI Docs"
|
||||
short_description: "Reference OpenAI docs, Codex self-knowledge, and model migration guidance"
|
||||
icon_small: "./assets/openai-small.svg"
|
||||
icon_large: "./assets/openai.png"
|
||||
default_prompt: "Use OpenAI Docs for official docs lookup, questions about Codex itself or Codex surfaces, model selection, model migration, and prompt-upgrade work."
|
||||
|
||||
dependencies:
|
||||
tools:
|
||||
- type: "mcp"
|
||||
value: "openaiDeveloperDocs"
|
||||
description: "OpenAI Developer Docs MCP server"
|
||||
transport: "streamable_http"
|
||||
url: "https://developers.openai.com/mcp"
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 14 14">
|
||||
<path d="M10.931 3.34a.112.112 0 0 0-.069-.104l-.038-.007c-1.537.05-2.45.318-3.714 1.002v6.683c.48-.248.936-.44 1.414-.58.695-.203 1.417-.292 2.303-.305l.038-.008a.113.113 0 0 0 .066-.104V3.341ZM2.363 9.919c0 .064.051.11.105.111l.33.008c1.162.046 2.042.243 2.975.662-.403-.585-1.008-1.075-1.654-1.292a.991.991 0 0 1-.674-.941v-5.14a6.36 6.36 0 0 0-.59-.076l-.37-.02a.115.115 0 0 0-.122.111v6.577Zm9.455-.001a.998.998 0 0 1-.877.992l-.101.007c-.832.012-1.47.095-2.066.27-.599.174-1.176.448-1.883.863a.444.444 0 0 1-.449 0c-1.299-.763-2.229-1.07-3.689-1.125l-.299-.008a.997.997 0 0 1-.977-.998V3.342c0-.573.478-1.017 1.038-.999l.417.023c.188.015.35.037.513.062v-.754c0-.708.749-1.244 1.429-.903.984.492 1.836 1.449 2.15 2.505 1.216-.617 2.222-.884 3.771-.934l.105.003a.998.998 0 0 1 .918.996v6.576ZM4.332 8.466c0 .049.03.087.07.1l.24.091a4.319 4.319 0 0 1 1.581 1.176V3.721c-.164-.803-.799-1.617-1.584-2.07l-.162-.088c-.025-.012-.054-.013-.088.009a.12.12 0 0 0-.057.102v6.792Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,37 @@
|
||||
# Latest model guide
|
||||
|
||||
This file is a curated helper. Every recommendation here must be verified against current OpenAI docs before it is repeated to a user.
|
||||
|
||||
## Current model map
|
||||
|
||||
| Model ID | Use for |
|
||||
| --- | --- |
|
||||
| `gpt-5.5` | Latest/default text and reasoning model for most new apps, including coding and tool-heavy workflows |
|
||||
| `gpt-5.5-pro` | Maximum reasoning or quality when latency and cost matter less |
|
||||
| `gpt-5.4` | Previous default text and reasoning model; use for existing GPT-5.4 integrations |
|
||||
| `gpt-5.4-mini` | Lower-cost testing and lighter production workflows |
|
||||
| `gpt-5.4-nano` | High-throughput simple tasks and classification |
|
||||
| `gpt-5.5` | Explicit no-reasoning text path via `reasoning.effort: none` |
|
||||
| `gpt-4.1-mini` | Cheaper no-reasoning text |
|
||||
| `gpt-4.1-nano` | Fastest and cheapest no-reasoning text |
|
||||
| `gpt-5.3-codex` | Agentic coding, code editing, and tool-heavy coding workflows |
|
||||
| `gpt-5.1-codex-mini` | Cheaper coding workflows |
|
||||
| `gpt-image-2` | Best image generation and edit quality |
|
||||
| `gpt-image-1.5` | Less expensive image generation and edit quality |
|
||||
| `gpt-image-1-mini` | Cost-optimized image generation |
|
||||
| `gpt-4o-mini-tts` | Text-to-speech |
|
||||
| `gpt-4o-mini-transcribe` | Speech-to-text, fast and cost-efficient |
|
||||
| `gpt-realtime-1.5` | Realtime voice and multimodal sessions |
|
||||
| `gpt-realtime-mini` | Cheaper realtime sessions |
|
||||
| `gpt-audio` | Chat Completions audio input and output |
|
||||
| `gpt-audio-mini` | Cheaper Chat Completions audio workflows |
|
||||
| `sora-2` | Faster iteration and draft video generation |
|
||||
| `sora-2-pro` | Higher-quality production video |
|
||||
| `omni-moderation-latest` | Text and image moderation |
|
||||
| `text-embedding-3-large` | Higher-quality retrieval embeddings; default in this skill because no best-specific row exists |
|
||||
| `text-embedding-3-small` | Lower-cost embeddings |
|
||||
|
||||
## Maintenance notes
|
||||
|
||||
- This file will drift unless it is periodically re-verified against current OpenAI docs.
|
||||
- If this file conflicts with current docs, the docs win.
|
||||
@@ -0,0 +1,244 @@
|
||||
GPT-5.5 works best when prompts define the outcome and leave room for the model to choose an efficient solution path. Compared with earlier models, you can often use shorter, more outcome-oriented prompts: describe what good looks like, what constraints matter, what evidence is available, and what the final answer should contain.
|
||||
|
||||
Avoid carrying over every instruction from an older prompt stack. Legacy prompts often over-specify the process because earlier models needed more help staying on track. With GPT-5.5, that can add noise, narrow the model's search space, or lead to overly mechanical answers.
|
||||
|
||||
For more detail on GPT-5.5 behavior changes, start with the [Using GPT-5.5 guide](/api/docs/guides/latest-model). This guide focuses on prompt changes that follow from those behavior changes.
|
||||
|
||||
The patterns here are starting points. Adapt them to your product surface, tools, evals, and user experience goals.
|
||||
|
||||
## Personality and behavior
|
||||
|
||||
GPT-5.5's default style is efficient, direct, and task-oriented. This is useful for production systems: responses stay focused, behavior is easier to steer, and the model avoids unnecessary conversational padding.
|
||||
|
||||
For customer-facing assistants, support workflows, coaching experiences, and other conversational products, define both personality and collaboration style.
|
||||
|
||||
- **Personality** controls how the assistant sounds: tone, warmth, directness, formality, humor, empathy, and level of polish.
|
||||
- **Collaboration style** controls how the assistant works: when it asks questions, when it makes assumptions, how proactive it should be, how much context it gives, when it checks work, and how it handles uncertainty or risk.
|
||||
|
||||
Keep both short. Personality instructions should shape the user experience. Collaboration instructions should shape task behavior. Neither should replace clear goals, success criteria, tool rules, or stopping conditions.
|
||||
|
||||
Example personality block for a steady task-focused assistant:
|
||||
|
||||
```text
|
||||
# Personality
|
||||
You are a capable collaborator: approachable, steady, and direct. Assume the user is competent and acting in good faith, and respond with patience, respect, and practical helpfulness.
|
||||
|
||||
Prefer making progress over stopping for clarification when the request is already clear enough to attempt. Use context and reasonable assumptions to move forward. Ask for clarification only when the missing information would materially change the answer or create meaningful risk, and keep any question narrow.
|
||||
|
||||
Stay concise without becoming curt. Give enough context for the user to understand and trust the answer, then stop. Use examples, comparisons, or simple analogies when they make the point easier to grasp. When correcting the user or disagreeing, be candid but constructive. When an error is pointed out, acknowledge it plainly and focus on fixing it.
|
||||
|
||||
Match the user's tone within professional bounds. Avoid emojis and profanity by default, unless the user explicitly asks for that style or has clearly established it as appropriate for the conversation.
|
||||
```
|
||||
|
||||
Example personality block for an expressive collaborative assistant:
|
||||
|
||||
```text
|
||||
# Personality
|
||||
Adopt a vivid conversational presence: intelligent, curious, playful when appropriate, and attentive to the user's thinking. Ask good questions when the problem is blurry, then become decisive once there is enough context.
|
||||
|
||||
Be warm, collaborative, and polished. Conversation should feel easy and alive, but not chatty for its own sake. Offer a real point of view rather than merely mirroring the user, while staying responsive to their goals and constraints.
|
||||
|
||||
Be thoughtful and grounded when the task calls for synthesis or advice. State a clear recommendation when you have enough context, explain important tradeoffs, and name uncertainty without becoming evasive.
|
||||
```
|
||||
|
||||
For more expressive products, add warmth, curiosity, humor, or point of view explicitly, but keep the block short. Use personality to shape the experience, not to compensate for unclear goals or missing task instructions.
|
||||
|
||||
## Improve time to first visible token with a preamble
|
||||
|
||||
In streaming applications, users notice how long it takes before the first visible response appears. GPT-5.5 may spend time reasoning, planning, or preparing tool calls before emitting visible text.
|
||||
|
||||
For longer or tool-heavy tasks, prompt the model to start with a short preamble: a brief visible update that acknowledges the request and states the first step. This can improve perceived responsiveness without changing the underlying task.
|
||||
|
||||
Use this pattern when the task may take more than one step, require tool calls, or involve a long-running agent workflow.
|
||||
|
||||
```text
|
||||
Before any tool calls for a multi-step task, send a short user-visible update that acknowledges the request and states the first step. Keep it to one or two sentences.
|
||||
```
|
||||
|
||||
For coding agents that expose separate message phases, you can be more explicit:
|
||||
|
||||
```text
|
||||
You must always start with an intermediary update before any content in the analysis channel if the task will require calling tools. The user update should acknowledge the request and explain your first step.
|
||||
```
|
||||
|
||||
## Outcome-first prompts and stopping conditions
|
||||
|
||||
GPT-5.5 is strongest when the prompt defines the target outcome, success criteria, constraints, and available context, then lets the model choose the path.
|
||||
|
||||
For many tasks, describe the destination rather than every step. This gives the model room to choose the right search, tool, or reasoning strategy for the task.
|
||||
|
||||
Prefer this:
|
||||
|
||||
```text
|
||||
Resolve the customer's issue end to end.
|
||||
|
||||
Success means:
|
||||
- the eligibility decision is made from the available policy and account data
|
||||
- any allowed action is completed before responding
|
||||
- the final answer includes completed_actions, customer_message, and blockers
|
||||
- if evidence is missing, ask for the smallest missing field
|
||||
```
|
||||
|
||||
**Avoid unnecessary absolute rules.** Older prompts often use strict instructions like `ALWAYS`, `NEVER`, `must`, and `only` to control model behavior. Use those words for true invariants, such as safety rules, required output fields, or actions that should never happen. For judgment calls, such as when to search, ask for clarification, use a tool, or keep iterating, prefer decision rules instead.
|
||||
|
||||
Avoid this style of instruction unless every step is truly required:
|
||||
|
||||
```text
|
||||
First inspect A, then inspect B, then compare every field, then think through
|
||||
all possible exceptions, then decide which tool to call, then call the tool,
|
||||
then explain the entire process to the user.
|
||||
```
|
||||
|
||||
Add explicit stopping conditions:
|
||||
|
||||
```text
|
||||
Resolve the user query in the fewest useful tool loops, but do not let loop minimization outrank correctness, accessible fallback evidence, calculations, or required citation tags for factual claims.
|
||||
|
||||
After each result, ask: "Can I answer the user's core request now with useful evidence and citations for the factual claims?" If yes, answer.
|
||||
```
|
||||
|
||||
Define missing-evidence behavior:
|
||||
|
||||
```text
|
||||
Use the minimum evidence sufficient to answer correctly, cite it precisely, then stop.
|
||||
```
|
||||
|
||||
## Formatting
|
||||
|
||||
GPT-5.5 is highly steerable on output format and structure. Use that control when it improves comprehension or product fit.
|
||||
|
||||
Set `text.verbosity`, describe the expected output shape, and reserve heavier structure for cases where it improves comprehension or your product UI needs a stable artifact. The API default for `text.verbosity` is `medium`; use `low` when you prefer shorter, more concise responses.
|
||||
|
||||
Plain conversational formatting:
|
||||
|
||||
```text
|
||||
Let formatting serve comprehension. Use plain paragraphs as the default format for normal conversation, explanations, reports, documentation, and technical writeups. Keep the presentation clean and readable without making the structure feel heavier than the content.
|
||||
|
||||
Use headers, bold text, bullets, and numbered lists sparingly. Reach for them when the user requests them, when the answer needs clear comparison or ranking, or when the information would be harder to scan as prose. Otherwise, favor short paragraphs and natural transitions.
|
||||
|
||||
Respect formatting preferences from the user. If they ask for a terse answer, minimal formatting, no bullets, no headers, or a specific structure, follow that preference unless there is a strong reason not to.
|
||||
```
|
||||
|
||||
Add explicit audience and length guidance:
|
||||
|
||||
```text
|
||||
Write for a senior business audience. Keep the answer under 400 words. Use short paragraphs and only include bullets when they improve scannability. Prioritize the conclusion first, then the reasoning, then caveats.
|
||||
```
|
||||
|
||||
For editing, rewriting, summaries, or customer-facing messages, tell the model what to preserve before asking it to improve style. This pattern is useful when you want polish without expansion.
|
||||
|
||||
```text
|
||||
Preserve the requested artifact, length, structure, and genre first. Quietly improve clarity, flow, and correctness. Do not add new claims, extra sections, or a more promotional tone unless explicitly requested.
|
||||
```
|
||||
|
||||
## Grounding, citations, and retrieval budgets
|
||||
|
||||
For grounded answers, citation behavior should be part of the prompt. Define what needs support, what counts as enough evidence, and how the model should behave when evidence is missing. Absence of evidence shouldn't automatically become a factual "no." For more details and examples, see the [citation formatting guide](/api/docs/guides/citation-formatting).
|
||||
|
||||
### Add an explicit retrieval budget
|
||||
|
||||
Retrieval budgets are stopping rules for search. They tell the model when enough evidence is enough.
|
||||
|
||||
```text
|
||||
For ordinary Q&A, start with one broad search using short, discriminative keywords. If the top results contain enough citable support for the core request, answer from those results instead of searching again.
|
||||
|
||||
Make another retrieval call only when:
|
||||
- The top results do not answer the core question.
|
||||
- A required fact, parameter, owner, date, ID, or source is missing.
|
||||
- The user asked for exhaustive coverage, a comparison, or a comprehensive list.
|
||||
- A specific document, URL, email, meeting, record, or code artifact must be read.
|
||||
- The answer would otherwise contain an important unsupported factual claim.
|
||||
|
||||
Do not search again to improve phrasing, add examples, cite nonessential details, or support wording that can safely be made more generic.
|
||||
```
|
||||
|
||||
## Creative drafting guardrails
|
||||
|
||||
For drafting tasks, tell the model which claims must come from sources and which parts may be creatively written. This is especially important for slides, launch copy, customer summaries, talk tracks, leadership blurbs, and narrative framing.
|
||||
|
||||
```text
|
||||
For creative or generative requests such as slides, leadership blurbs, outbound copy, summaries for sharing, talk tracks, or narrative framing, distinguish source-backed facts from creative wording.
|
||||
|
||||
- Use retrieved or provided facts for concrete product, customer, metric, roadmap, date, capability, and competitive claims, and cite those claims.
|
||||
- Do not invent specific names, first-party data claims, metrics, roadmap status, customer outcomes, or product capabilities to make the draft sound stronger.
|
||||
- If there is little or no citable support, write a useful generic draft with placeholders or clearly labeled assumptions rather than unsupported specifics.
|
||||
```
|
||||
|
||||
## Frontend engineering and visual taste
|
||||
|
||||
For frontend work, refer to the [example instructions](/api/docs/guides/frontend-prompt) for practical ways to steer UI quality. They cover product and user context, design-system alignment, first-screen usability, familiar controls, expected states, responsive behavior, and common generated-UI defaults to avoid, such as generic heroes, nested cards, decorative gradients, visible instructional text, and broken layouts.
|
||||
|
||||
## Prompt the model to check its work
|
||||
|
||||
Give GPT-5.5 access to tools that let it check outputs when validation is possible.
|
||||
|
||||
For coding agents, ask for concrete validation commands:
|
||||
|
||||
```text
|
||||
After making changes, run the most relevant validation available:
|
||||
- targeted unit tests for changed behavior
|
||||
- type checks or lint checks when applicable
|
||||
- build checks for affected packages
|
||||
- a minimal smoke test when full validation is too expensive
|
||||
|
||||
If validation cannot be run, explain why and describe the next best check.
|
||||
```
|
||||
|
||||
For visual artifacts, ask for inspection after rendering:
|
||||
|
||||
```text
|
||||
Render the artifact before finalizing. Inspect the rendered output for layout, clipping, spacing, missing content, and visual consistency. Revise until the rendered output matches the requirements.
|
||||
```
|
||||
|
||||
For engineering and planning tasks, make implementation plans traceable:
|
||||
|
||||
```text
|
||||
For implementation plans, include:
|
||||
- requirements and where each is addressed
|
||||
- named resources, files, APIs, or systems involved
|
||||
- state transitions or data flow where relevant
|
||||
- validation commands or checks
|
||||
- failure behavior
|
||||
- privacy and security considerations
|
||||
- open questions that materially affect implementation
|
||||
```
|
||||
|
||||
## Phase parameter
|
||||
|
||||
Starting with GPT-5.4, long-running or tool-heavy Responses workflows can use assistant-item `phase` values to distinguish intermediate updates from final answers. GPT-5.5 uses the same pattern.
|
||||
|
||||
If you use `previous_response_id`, the API preserves prior assistant state automatically. If your application manually replays assistant output items into the next request, preserve each original `phase` value and pass it back unchanged. This matters most when a response includes preambles, repeated tool calls, or a final answer after intermediate assistant updates.
|
||||
|
||||
```text
|
||||
If manually replaying assistant items:
|
||||
- Preserve assistant `phase` values exactly.
|
||||
- Use `phase: "commentary"` for intermediate user-visible updates.
|
||||
- Use `phase: "final_answer"` for the completed answer.
|
||||
- Do not add `phase` to user messages.
|
||||
```
|
||||
|
||||
## Suggested prompt structure
|
||||
|
||||
Use this structure as a starting point for complex prompts. Keep each section short. Add detail only where it changes behavior.
|
||||
|
||||
```text
|
||||
Role: [1-2 sentences defining the model's function, context, and job]
|
||||
|
||||
# Personality
|
||||
[tone, demeanor, and collaboration style]
|
||||
|
||||
# Goal
|
||||
[user-visible outcome]
|
||||
|
||||
# Success criteria
|
||||
[what must be true before the final answer]
|
||||
|
||||
# Constraints
|
||||
[policy, safety, business, evidence, and side-effect limits]
|
||||
|
||||
# Output
|
||||
[sections, length, and tone]
|
||||
|
||||
# Stop rules
|
||||
[when to retry, fallback, abstain, ask, or stop]
|
||||
```
|
||||
@@ -0,0 +1,181 @@
|
||||
# Upgrading to GPT-5.5
|
||||
|
||||
Use this guide when the user explicitly asks to upgrade an existing integration to GPT-5.5. Pair it with current OpenAI docs lookups. The default target string is `gpt-5.5`.
|
||||
|
||||
## Freshness check
|
||||
|
||||
Before applying this bundled guide for a latest/current/default model upgrade, run `node scripts/resolve-latest-model-info.js` from the OpenAI Docs skill directory.
|
||||
|
||||
- If the command returns `modelSlug: "gpt-5p5"`, continue with this bundled guide and use `references/prompting-guide.md` when prompt updates are needed.
|
||||
- If the command returns a different `modelSlug`, fetch both the returned `migrationGuideUrl` and `promptingGuideUrl` and use them as the current source of truth instead of the bundled references.
|
||||
- If the command fails, metadata is missing, or either remote guide cannot be fetched, continue with bundled fallback references and say the remote freshness check was unavailable.
|
||||
- If the user explicitly named a target model, preserve that target and use current docs only to check compatibility or caveats.
|
||||
|
||||
## Upgrade posture
|
||||
|
||||
Upgrade with the narrowest safe change set:
|
||||
|
||||
- replace the model string first
|
||||
- update only the prompts that are directly tied to that model usage
|
||||
- do not automatically upgrade older or ambiguous model usages that may be intentionally pinned, such as historical docs, examples, tests, eval baselines, comparison code, or low-cost fallback/routing paths. Unless the user explicitly asks to upgrade all model usage, leave those sites unchanged and list them as confirmation-needed
|
||||
- prefer prompt-only upgrades when possible
|
||||
- if the upgrade would require API-surface changes, parameter rewrites, tool rewiring, provider migration, or broader code edits, mark it as blocked instead of stretching the scope
|
||||
|
||||
## Upgrade workflow
|
||||
|
||||
1. Inventory current model usage.
|
||||
- Search for model strings, client calls, and prompt-bearing files.
|
||||
- Include inline prompts, prompt templates, YAML or JSON configs, Markdown docs, and saved prompts when they are clearly tied to a model usage site.
|
||||
2. Pair each model usage with its prompt surface.
|
||||
- Prefer the closest prompt surface first: inline system or developer text, then adjacent prompt files, then shared templates.
|
||||
- If you cannot confidently tie a prompt to the model usage, say so instead of guessing.
|
||||
3. Classify the source model family.
|
||||
- Common buckets: GPT-5.4, GPT-5.3-Codex or GPT-5.2-Codex, earlier GPT-5.x, GPT-4o or GPT-4.1, reasoning models such as o1 or o3 or o4-mini, third-party model, or mixed and unclear.
|
||||
4. Decide the upgrade class.
|
||||
- `model string only`
|
||||
- `model string + light prompt rewrite`
|
||||
- `blocked without code changes`
|
||||
5. Run the compatibility gate.
|
||||
- Check whether the current integration can accept `gpt-5.5` without API-surface changes or implementation changes.
|
||||
- Check whether structured outputs, tool schemas, function names, and downstream parsers can remain unchanged.
|
||||
- For long-running Responses or tool-heavy agents, check whether `phase` is already preserved or round-tripped when the host replays assistant items or uses preambles.
|
||||
- If compatibility depends on code changes, return `blocked`.
|
||||
- If compatibility is unclear, return `unknown` rather than improvising.
|
||||
6. Apply the upgrade when it is in scope.
|
||||
- Default replacement string: `gpt-5.5`.
|
||||
- Keep the intervention small and behavior-preserving.
|
||||
- Start from the current reasoning effort when it is visible unless there is a measured reason to change it.
|
||||
- For in-scope changes, update the model string and directly related prompts.
|
||||
- For blocked or unknown changes, do not edit; report the blocker or uncertainty.
|
||||
7. Summarize the result.
|
||||
- `Current model usage`
|
||||
- `Model-string updates`
|
||||
- `Reasoning-effort handling`
|
||||
- `Prompt updates`
|
||||
- `Structured output and formatting assessment`
|
||||
- `Tool-use assessment` when the flow uses tools, retrieval, or terminal actions
|
||||
- `Phase assessment` when the flow is long-running, replayed, or tool-heavy
|
||||
- `Compatibility check`
|
||||
- `Validation performed`
|
||||
|
||||
Output rule:
|
||||
|
||||
- For each usage site, state the starting reasoning-effort recommendation.
|
||||
- If the repo exposes the current reasoning setting, recommend preserving it first unless current OpenAI docs say otherwise.
|
||||
- If the repo does not expose the current setting, recommend not adding one unless current OpenAI docs require it.
|
||||
|
||||
## Upgrade outcomes
|
||||
|
||||
### `model string only`
|
||||
|
||||
Choose this when:
|
||||
|
||||
- the source model is GPT-5.4
|
||||
- the existing prompts are already short, explicit, and task-bounded
|
||||
- the workflow does not rely on strict output formats, tool-call behavior, batch completeness, or long-horizon execution that should be validated after the upgrade
|
||||
- there are no obvious compatibility blockers
|
||||
|
||||
Default action:
|
||||
|
||||
- replace the model string with `gpt-5.5`
|
||||
- preserve the current reasoning effort
|
||||
- keep prompts unchanged
|
||||
- validate behavior with existing tests, realistic spot checks, or an existing eval suite when one is already available
|
||||
|
||||
### `model string + light prompt rewrite`
|
||||
|
||||
Choose this when:
|
||||
|
||||
- the task needs stronger completeness, citation discipline, verification, or dependency handling
|
||||
- the upgraded model becomes too verbose, too dense, or hard to scan unless formatting is constrained
|
||||
- the workflow has strict output shape requirements and lacks an explicit format contract, schema, or parser validation
|
||||
- the workflow is research-heavy and needs stronger handling of sparse or empty retrieval results
|
||||
- the workflow is coding-oriented, terminal-based, tool-heavy, or multi-agent, but the existing API surface and tool definitions can remain unchanged
|
||||
|
||||
Default action:
|
||||
|
||||
- replace the model string with `gpt-5.5`
|
||||
- preserve the current reasoning effort for the first pass
|
||||
- make only the smallest prompt edits needed for the observed workflow risk
|
||||
- read the [GPT-5.5 prompting guide](/api/docs/guides/prompt-guidance?model=gpt-5.5) to choose the smallest prompt changes that recover or improve behavior
|
||||
- avoid broad prompt cleanup unrelated to the upgrade
|
||||
- for research workflows, add citation rules, retrieval budgets, missing-evidence behavior, and validation guidance from the prompting guide
|
||||
- for dependency-aware or tool-heavy workflows, add prerequisite checks, missing-context handling, explicit tool budgets, stop conditions, and validation guidance
|
||||
- for coding or terminal workflows, add repo-specific constraints, acceptance criteria, and concrete validation commands
|
||||
- for multi-agent support or triage workflows, add task ownership, handoff, completeness, and stopping criteria
|
||||
- for long-running Responses agents with preambles or multiple assistant messages, explicitly review whether `phase` is already handled; if adding or preserving `phase` would require code edits, mark the path as `blocked`
|
||||
- do not classify a coding or tool-using Responses workflow as `blocked` just because the visible snippet is minimal; prefer `model string + light prompt rewrite` unless the repo clearly shows that a safe GPT-5.5 path would require host-side code changes
|
||||
|
||||
### `blocked`
|
||||
|
||||
Choose this when:
|
||||
|
||||
- the upgrade appears to require API-surface changes
|
||||
- the upgrade appears to require parameter rewrites or reasoning-setting changes that are not exposed outside implementation code
|
||||
- the upgrade would require changing tool definitions, tool handler wiring, or schema contracts
|
||||
- the user is asking for a tooling, IDE, plugin, shell, or environment migration rather than a model and prompt migration
|
||||
- the integration depends on provider-specific APIs that do not map to the current OpenAI API surface without implementation work
|
||||
- you cannot confidently identify the prompt surface tied to the model usage
|
||||
|
||||
Default action:
|
||||
|
||||
- do not improvise a broader upgrade
|
||||
- report the blocker and explain that the fix is out of scope for this guide
|
||||
- if useful, describe the smallest follow-up implementation task that would unblock the migration
|
||||
|
||||
## Compatibility checklist
|
||||
|
||||
Before applying or recommending a model-and-prompt-only upgrade, check:
|
||||
|
||||
1. Can the current host accept the `gpt-5.5` model string without changing client code or API surface?
|
||||
2. Are the related prompts identifiable and editable?
|
||||
3. Does the host depend on behavior that likely needs API-surface changes, parameter rewrites, provider migration, or tool rewiring?
|
||||
4. Would the likely fix be prompt-only, or would it need implementation changes?
|
||||
5. Is the prompt surface close enough to the model usage that you can make a targeted change instead of a broad cleanup?
|
||||
6. Do strict structured outputs, schemas, or downstream parsers still have an explicit contract?
|
||||
7. For long-running Responses or tool-heavy agents, is `phase` already preserved if the host relies on preambles, replayed assistant items, or multiple assistant messages?
|
||||
8. Are latency, token, or price assumptions validated by tests, realistic spot checks, or an existing eval suite rather than inferred from general model positioning?
|
||||
|
||||
If item 1 is no, items 3 through 4 point to implementation work, or item 7 is no and the fix needs code changes, return `blocked`.
|
||||
|
||||
If item 2 is no, return `unknown` unless the user can point to the prompt location.
|
||||
|
||||
Important:
|
||||
|
||||
- Existing use of tools, agents, or multiple usage sites is not by itself a blocker.
|
||||
- If the current host can keep the same API surface and the same tool definitions, prefer `model string + light prompt rewrite` over `blocked`.
|
||||
- Reserve `blocked` for cases that truly require implementation changes, not cases that only need stronger prompt steering.
|
||||
- Do not claim token savings without task-level validation.
|
||||
|
||||
## Scope boundaries
|
||||
|
||||
This guide may:
|
||||
|
||||
- update or recommend updated model strings
|
||||
- update or recommend updated prompts
|
||||
- inspect code and prompt files to understand where those changes belong
|
||||
- inspect whether existing Responses flows already preserve `phase`
|
||||
- flag compatibility blockers
|
||||
- propose validation with existing tests, realistic spot checks, or existing eval suites
|
||||
|
||||
This guide may not:
|
||||
|
||||
- move Chat Completions code to Responses
|
||||
- move Responses code to another API surface
|
||||
- migrate SDKs, APIs, IDE configuration, shell hooks, plugins, or provider-specific tooling
|
||||
- rewrite parameter shapes
|
||||
- change tool definitions or tool-call handling
|
||||
- change structured-output wiring
|
||||
- add or retrofit `phase` handling in implementation code
|
||||
- edit business logic, orchestration logic, SDK usage, IDE configuration, shell hooks, or plugin integration behavior except for model-string replacements and directly related prompt edits
|
||||
|
||||
If a safe GPT-5.5 upgrade requires any of those changes, mark the path as blocked and out of scope.
|
||||
|
||||
## Validation plan
|
||||
|
||||
- Validate each upgraded usage site with existing tests, realistic spot checks, or an existing eval suite when one is already available.
|
||||
- Compare against the current GPT-5.4 baseline when available.
|
||||
- Check task success, retry count, tool-call count, total tokens, latency, output shape, and user-visible quality.
|
||||
- For specialized workflows, validate the contract that matters most instead of judging only general output quality.
|
||||
- If prompt edits were added, confirm each block is doing real work instead of adding noise.
|
||||
- If the workflow has downstream impact, add a lightweight verification pass before finalization.
|
||||
@@ -0,0 +1,598 @@
|
||||
#!/usr/bin/env node
|
||||
import {
|
||||
access,
|
||||
mkdir,
|
||||
readFile,
|
||||
rename,
|
||||
rm,
|
||||
stat,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { constants as fsConstants } from "node:fs";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { inspect, promisify } from "node:util";
|
||||
|
||||
const DEFAULT_MANUAL_URL = "https://developers.openai.com/codex/codex-manual.md";
|
||||
const DEFAULT_CACHE_DIR_NAME = "openai-docs-cache";
|
||||
const CACHE_FILE_NAME = "codex-manual.md";
|
||||
const OUTLINE_FILE_NAME = "codex-manual.outline.md";
|
||||
const HASH_HEADER = "x-content-sha256";
|
||||
const USER_AGENT = "codex-openai-docs";
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
class ManualFetchError extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "ManualFetchError";
|
||||
}
|
||||
}
|
||||
|
||||
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
||||
|
||||
const withTimeout = async (promiseFactory, timeoutMs) => {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
return await promiseFactory(controller.signal);
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
};
|
||||
|
||||
const proxyConfigured = () =>
|
||||
process.env.HTTP_PROXY ||
|
||||
process.env.HTTPS_PROXY ||
|
||||
process.env.http_proxy ||
|
||||
process.env.https_proxy;
|
||||
|
||||
const responseHeaders = (headers) => ({
|
||||
get(name) {
|
||||
return headers.get(name.toLowerCase()) ?? null;
|
||||
},
|
||||
});
|
||||
|
||||
const makeResponse = ({ body, headers, status }) => ({
|
||||
headers: responseHeaders(headers),
|
||||
ok: status >= 200 && status < 300,
|
||||
status,
|
||||
async text() {
|
||||
return body;
|
||||
},
|
||||
});
|
||||
|
||||
const parseCurlHeaders = (rawHeaders) => {
|
||||
const normalized = rawHeaders.replace(/\r\n/g, "\n").trim();
|
||||
const blocks = normalized.split(/\n\n+/).filter(Boolean);
|
||||
const headerBlock = [...blocks]
|
||||
.reverse()
|
||||
.find((block) => block.startsWith("HTTP/"));
|
||||
|
||||
if (!headerBlock) {
|
||||
throw new ManualFetchError("curl did not return HTTP response headers.");
|
||||
}
|
||||
|
||||
const [statusLine, ...lines] = headerBlock.split("\n");
|
||||
const statusMatch = /^HTTP\/\S+\s+(\d{3})/.exec(statusLine);
|
||||
if (!statusMatch) {
|
||||
throw new ManualFetchError(
|
||||
`Could not parse HTTP status from curl response: ${statusLine}`
|
||||
);
|
||||
}
|
||||
|
||||
const headers = new Map();
|
||||
lines.forEach((line) => {
|
||||
const separator = line.indexOf(":");
|
||||
if (separator === -1) return;
|
||||
const name = line.slice(0, separator).trim().toLowerCase();
|
||||
const value = line.slice(separator + 1).trim();
|
||||
headers.set(name, value);
|
||||
});
|
||||
|
||||
return {
|
||||
headers,
|
||||
status: Number(statusMatch[1]),
|
||||
};
|
||||
};
|
||||
|
||||
const tempFilePath = (cacheDir, suffix) =>
|
||||
path.join(
|
||||
cacheDir,
|
||||
`.fetch-codex-manual-${process.pid}-${Date.now()}-${Math.random()
|
||||
.toString(16)
|
||||
.slice(2)}${suffix}`
|
||||
);
|
||||
|
||||
const requestManualWithCurl = async (url, { cacheDir, method, timeoutMs }) => {
|
||||
const headerPath = tempFilePath(cacheDir, ".headers");
|
||||
const bodyPath = tempFilePath(cacheDir, ".body");
|
||||
const curlNames =
|
||||
process.platform === "win32" ? ["curl.exe", "curl"] : ["curl"];
|
||||
const args = [
|
||||
"--silent",
|
||||
"--show-error",
|
||||
"--location",
|
||||
"--dump-header",
|
||||
headerPath,
|
||||
"--output",
|
||||
bodyPath,
|
||||
"--user-agent",
|
||||
USER_AGENT,
|
||||
"--max-time",
|
||||
String(Math.max(1, Math.ceil(timeoutMs / 1000))),
|
||||
];
|
||||
|
||||
if (method === "HEAD") {
|
||||
args.push("--head");
|
||||
} else {
|
||||
args.push("--request", method);
|
||||
}
|
||||
args.push(url);
|
||||
|
||||
let lastError;
|
||||
for (const curlName of curlNames) {
|
||||
try {
|
||||
await execFileAsync(curlName, args, { windowsHide: true });
|
||||
const [rawHeaders, body] = await Promise.all([
|
||||
readFile(headerPath, "utf8"),
|
||||
readFile(bodyPath, "utf8"),
|
||||
]);
|
||||
const { headers, status } = parseCurlHeaders(rawHeaders);
|
||||
return makeResponse({ body, headers, status });
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
if (error?.code !== "ENOENT") break;
|
||||
} finally {
|
||||
await Promise.all([
|
||||
rm(headerPath, { force: true }),
|
||||
rm(bodyPath, { force: true }),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastError?.code === "ENOENT") {
|
||||
throw new ManualFetchError("curl is unavailable in this environment.", {
|
||||
cause: lastError,
|
||||
});
|
||||
}
|
||||
throw new ManualFetchError(`${method} ${url} could not be fetched.`, {
|
||||
cause: lastError,
|
||||
});
|
||||
};
|
||||
|
||||
const requestManualWithFetch = async (url, { method, timeoutMs }) => {
|
||||
if (typeof fetch !== "function") {
|
||||
throw new ManualFetchError(
|
||||
"Native fetch is unavailable in this Node runtime."
|
||||
);
|
||||
}
|
||||
|
||||
return withTimeout(
|
||||
(signal) =>
|
||||
fetch(url, {
|
||||
method,
|
||||
headers: { "User-Agent": USER_AGENT },
|
||||
signal,
|
||||
}),
|
||||
timeoutMs
|
||||
);
|
||||
};
|
||||
|
||||
const requestManual = async (url, { cacheDir, method, timeoutMs }) => {
|
||||
const preferCurl = Boolean(proxyConfigured()) || typeof fetch !== "function";
|
||||
const transports = preferCurl
|
||||
? [
|
||||
() => requestManualWithCurl(url, { cacheDir, method, timeoutMs }),
|
||||
() => requestManualWithFetch(url, { method, timeoutMs }),
|
||||
]
|
||||
: [
|
||||
() => requestManualWithFetch(url, { method, timeoutMs }),
|
||||
() => requestManualWithCurl(url, { cacheDir, method, timeoutMs }),
|
||||
];
|
||||
|
||||
let lastError;
|
||||
for (const transport of transports) {
|
||||
try {
|
||||
const response = await transport();
|
||||
if (!response.ok) {
|
||||
throw new ManualFetchError(
|
||||
`${method} ${url} failed with HTTP ${response.status}.`
|
||||
);
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ManualFetchError(`${method} ${url} could not be fetched.`, {
|
||||
cause: lastError,
|
||||
});
|
||||
};
|
||||
|
||||
const readHeaderSha = (response) => {
|
||||
const value = response.headers.get(HASH_HEADER);
|
||||
if (!value || !/^[a-f0-9]{64}$/i.test(value)) {
|
||||
throw new ManualFetchError(`Manual response is missing ${HASH_HEADER}.`);
|
||||
}
|
||||
return value.toLowerCase();
|
||||
};
|
||||
|
||||
const nearestExistingParent = async (target) => {
|
||||
let current = target;
|
||||
while (true) {
|
||||
try {
|
||||
const info = await stat(current);
|
||||
return info.isDirectory() ? current : null;
|
||||
} catch (error) {
|
||||
if (error?.code !== "ENOENT") return null;
|
||||
}
|
||||
|
||||
const parent = path.dirname(current);
|
||||
if (parent === current) return null;
|
||||
current = parent;
|
||||
}
|
||||
};
|
||||
|
||||
const usableCacheDir = async (cacheDir) => {
|
||||
if (!cacheDir) return null;
|
||||
const resolved = path.resolve(cacheDir);
|
||||
|
||||
try {
|
||||
const info = await stat(resolved);
|
||||
if (!info.isDirectory()) return null;
|
||||
} catch (error) {
|
||||
if (error?.code !== "ENOENT") return null;
|
||||
}
|
||||
|
||||
const parent = await nearestExistingParent(resolved);
|
||||
if (!parent) return null;
|
||||
|
||||
try {
|
||||
await access(parent, fsConstants.W_OK | fsConstants.X_OK);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
};
|
||||
|
||||
const defaultCacheDirCandidates = () => {
|
||||
const candidates = [];
|
||||
const seen = new Set();
|
||||
const pushCandidate = (candidate) => {
|
||||
if (!candidate || seen.has(candidate)) return;
|
||||
seen.add(candidate);
|
||||
candidates.push(candidate);
|
||||
};
|
||||
|
||||
[process.env.TMPDIR, process.env.TEMP, process.env.TMP].forEach((baseDir) => {
|
||||
if (baseDir) {
|
||||
pushCandidate(path.join(baseDir, DEFAULT_CACHE_DIR_NAME));
|
||||
}
|
||||
});
|
||||
|
||||
if (process.platform !== "win32") {
|
||||
pushCandidate(`/private/tmp/${DEFAULT_CACHE_DIR_NAME}`);
|
||||
pushCandidate(`/tmp/${DEFAULT_CACHE_DIR_NAME}`);
|
||||
}
|
||||
|
||||
return candidates;
|
||||
};
|
||||
|
||||
const resolveCacheDir = async (cacheDir) => {
|
||||
if (cacheDir) {
|
||||
return usableCacheDir(cacheDir);
|
||||
}
|
||||
|
||||
for (const candidate of defaultCacheDirCandidates()) {
|
||||
const usable = await usableCacheDir(candidate);
|
||||
if (usable) return usable;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const cacheFilePath = (cacheDir) => path.join(cacheDir, CACHE_FILE_NAME);
|
||||
|
||||
const outlineFilePath = (cacheDir) => path.join(cacheDir, OUTLINE_FILE_NAME);
|
||||
|
||||
const manualLines = (manual) => {
|
||||
const lines = manual.replace(/\r\n/g, "\n").split("\n");
|
||||
if (lines[lines.length - 1] === "") lines.pop();
|
||||
return lines;
|
||||
};
|
||||
|
||||
const sectionTitle = (rawTitle) =>
|
||||
rawTitle.replace(/\s+#+\s*$/, "").replace(/\s+/g, " ").trim();
|
||||
|
||||
const buildOutline = (manual) => {
|
||||
const lines = manualLines(manual);
|
||||
const headings = [];
|
||||
let inFence = false;
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
if (/^\s*(```|~~~)/.test(line)) {
|
||||
inFence = !inFence;
|
||||
return;
|
||||
}
|
||||
if (inFence) return;
|
||||
|
||||
const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
|
||||
if (!match) return;
|
||||
|
||||
const level = match[1].length;
|
||||
if (level < 2 || level > 3) return;
|
||||
|
||||
headings.push({
|
||||
level,
|
||||
title: sectionTitle(match[2]),
|
||||
startLine: index + 1,
|
||||
endLine: lines.length,
|
||||
});
|
||||
});
|
||||
|
||||
for (let index = 0; index < headings.length; index += 1) {
|
||||
const heading = headings[index];
|
||||
const nextPeer = headings
|
||||
.slice(index + 1)
|
||||
.find((candidate) => candidate.level <= heading.level);
|
||||
if (nextPeer) {
|
||||
heading.endLine = nextPeer.startLine - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (headings.length === 0) {
|
||||
return {
|
||||
headingCount: 0,
|
||||
lineCount: lines.length,
|
||||
text: "No markdown headings found.",
|
||||
};
|
||||
}
|
||||
|
||||
const minLevel = Math.min(...headings.map((heading) => heading.level));
|
||||
return {
|
||||
headingCount: headings.length,
|
||||
lineCount: lines.length,
|
||||
text: headings
|
||||
.map((heading) => {
|
||||
const indent = " ".repeat(heading.level - minLevel);
|
||||
return `${indent}- ${heading.title} (lines ${heading.startLine}-${heading.endLine})`;
|
||||
})
|
||||
.join("\n"),
|
||||
};
|
||||
};
|
||||
|
||||
const outlineMarkdown = (outline) => `# Codex Manual Outline\n\n${outline.text}\n`;
|
||||
|
||||
const manualStatusLine = (status) =>
|
||||
status.cacheStatus === "hit"
|
||||
? "Manual status: local manual was already current."
|
||||
: "Manual status: local manual was updated.";
|
||||
|
||||
const formatResult = ({ status, outlineText }) =>
|
||||
[
|
||||
`Manual path: ${status.manualPath}`,
|
||||
`Outline path: ${status.outlinePath}`,
|
||||
manualStatusLine(status),
|
||||
"",
|
||||
outlineText,
|
||||
].join("\n");
|
||||
|
||||
const readCachedManual = async (cacheDir, expectedSha256) => {
|
||||
try {
|
||||
const manual = await readFile(cacheFilePath(cacheDir), "utf8");
|
||||
return sha256(manual) === expectedSha256 ? manual : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const writeCachedManual = async (cacheDir, manual) => {
|
||||
await mkdir(cacheDir, { recursive: true });
|
||||
const tmpPath = tempFilePath(cacheDir, `.${CACHE_FILE_NAME}.tmp`);
|
||||
await writeFile(tmpPath, manual, "utf8");
|
||||
await rename(tmpPath, cacheFilePath(cacheDir));
|
||||
};
|
||||
|
||||
const writeOutline = async (cacheDir, outlineText) => {
|
||||
await mkdir(cacheDir, { recursive: true });
|
||||
const tmpPath = tempFilePath(cacheDir, `.${OUTLINE_FILE_NAME}.tmp`);
|
||||
await writeFile(tmpPath, outlineText, "utf8");
|
||||
await rename(tmpPath, outlineFilePath(cacheDir));
|
||||
};
|
||||
|
||||
const fetchCodexManual = async ({
|
||||
manualUrl = DEFAULT_MANUAL_URL,
|
||||
cacheDir,
|
||||
timeoutMs = 30000,
|
||||
} = {}) => {
|
||||
const resolvedCacheDir = await resolveCacheDir(cacheDir);
|
||||
if (!resolvedCacheDir) {
|
||||
throw new ManualFetchError(
|
||||
"Manual cache directory is unavailable; pass --cache-dir to override or use OpenAI Docs MCP fallback."
|
||||
);
|
||||
}
|
||||
await mkdir(resolvedCacheDir, { recursive: true });
|
||||
|
||||
const headResponse = await requestManual(manualUrl, {
|
||||
cacheDir: resolvedCacheDir,
|
||||
method: "HEAD",
|
||||
timeoutMs,
|
||||
});
|
||||
const expectedSha256 = readHeaderSha(headResponse);
|
||||
const manualPath = cacheFilePath(resolvedCacheDir);
|
||||
const outlinePath = outlineFilePath(resolvedCacheDir);
|
||||
const checkedAt = new Date().toISOString();
|
||||
|
||||
const cachedManual = await readCachedManual(resolvedCacheDir, expectedSha256);
|
||||
if (cachedManual !== null) {
|
||||
const outline = buildOutline(cachedManual);
|
||||
const outlineText = outlineMarkdown(outline);
|
||||
await writeOutline(resolvedCacheDir, outlineText);
|
||||
|
||||
return {
|
||||
outlineText,
|
||||
status: {
|
||||
manualUrl,
|
||||
headerSha256: expectedSha256,
|
||||
fetchedManualSha256: expectedSha256,
|
||||
manualHashMatches: true,
|
||||
cacheStatus: "hit",
|
||||
cacheDir: resolvedCacheDir,
|
||||
manualPath,
|
||||
outlinePath,
|
||||
checkedAt,
|
||||
lineCount: outline.lineCount,
|
||||
headingCount: outline.headingCount,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const getResponse = await requestManual(manualUrl, {
|
||||
cacheDir: resolvedCacheDir,
|
||||
method: "GET",
|
||||
timeoutMs,
|
||||
});
|
||||
const getHeaderSha256 = readHeaderSha(getResponse);
|
||||
if (getHeaderSha256 !== expectedSha256) {
|
||||
throw new ManualFetchError(
|
||||
`${HASH_HEADER} changed between HEAD and GET for ${manualUrl}.`
|
||||
);
|
||||
}
|
||||
|
||||
const manualText = await getResponse.text();
|
||||
const actualSha256 = sha256(manualText);
|
||||
const manualHashMatches = actualSha256 === expectedSha256;
|
||||
if (!manualHashMatches) {
|
||||
throw new ManualFetchError(
|
||||
`${HASH_HEADER} did not match the fetched manual body for ${manualUrl}.`
|
||||
);
|
||||
}
|
||||
|
||||
await writeCachedManual(resolvedCacheDir, manualText);
|
||||
const outline = buildOutline(manualText);
|
||||
const outlineText = outlineMarkdown(outline);
|
||||
await writeOutline(resolvedCacheDir, outlineText);
|
||||
|
||||
return {
|
||||
outlineText,
|
||||
status: {
|
||||
manualUrl,
|
||||
headerSha256: expectedSha256,
|
||||
fetchedManualSha256: actualSha256,
|
||||
manualHashMatches,
|
||||
cacheStatus: "updated",
|
||||
cacheDir: resolvedCacheDir,
|
||||
manualPath,
|
||||
outlinePath,
|
||||
checkedAt,
|
||||
lineCount: outline.lineCount,
|
||||
headingCount: outline.headingCount,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const parseArgs = (argv) => {
|
||||
const args = {
|
||||
manualUrl: DEFAULT_MANUAL_URL,
|
||||
cacheDir: undefined,
|
||||
timeoutMs: 30000,
|
||||
statusJson: false,
|
||||
};
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
if (arg === "--manual-url") {
|
||||
args.manualUrl = argv[++index];
|
||||
} else if (arg === "--cache-dir") {
|
||||
args.cacheDir = argv[++index];
|
||||
} else if (arg === "--timeout-ms") {
|
||||
args.timeoutMs = Number(argv[++index]);
|
||||
} else if (arg === "--status-json") {
|
||||
args.statusJson = true;
|
||||
} else {
|
||||
throw new ManualFetchError(`Unknown argument: ${arg}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.manualUrl) {
|
||||
throw new ManualFetchError("--manual-url cannot be empty.");
|
||||
}
|
||||
if (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0) {
|
||||
throw new ManualFetchError("--timeout-ms must be a positive number.");
|
||||
}
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
const args = parseArgs(process.argv.slice(2));
|
||||
const { outlineText, status } = await fetchCodexManual(args);
|
||||
|
||||
process.stdout.write(formatResult({ status, outlineText }));
|
||||
|
||||
if (args.statusJson) {
|
||||
console.error(JSON.stringify(status));
|
||||
}
|
||||
};
|
||||
|
||||
const envProxyHint = () => {
|
||||
if (proxyConfigured()) {
|
||||
return "Hint: proxy env vars are present. This helper prefers `curl` in proxied sessions; if requests still fail, verify `curl` is installed and the proxy configuration is valid.";
|
||||
}
|
||||
if (typeof fetch !== "function") {
|
||||
return "Hint: native fetch is unavailable in this Node runtime. Install `curl` or use a newer Node version to fetch the manual.";
|
||||
}
|
||||
if (process.platform === "win32") {
|
||||
return "Hint: on Windows, pass a cache dir under `%TEMP%` or `%TMP%`.";
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const formatErrorDetails = (error) => {
|
||||
const details = inspect(error, {
|
||||
breakLength: 120,
|
||||
colors: false,
|
||||
compact: false,
|
||||
depth: 8,
|
||||
});
|
||||
if (!error?.cause) {
|
||||
return details;
|
||||
}
|
||||
|
||||
return `${details}\n\nCause:\n${inspect(error.cause, {
|
||||
breakLength: 120,
|
||||
colors: false,
|
||||
compact: false,
|
||||
depth: 8,
|
||||
})}`;
|
||||
};
|
||||
|
||||
const isCliEntrypoint = () => {
|
||||
const entrypoint = process.argv[1];
|
||||
if (!entrypoint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pathToFileURL(entrypoint).href === import.meta.url;
|
||||
};
|
||||
|
||||
if (isCliEntrypoint()) {
|
||||
main().catch((error) => {
|
||||
console.error(`Error: ${error.message}`);
|
||||
const hint = envProxyHint();
|
||||
if (hint) {
|
||||
console.error(hint);
|
||||
}
|
||||
console.error("");
|
||||
console.error("Details:");
|
||||
console.error(formatErrorDetails(error));
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
|
||||
export { DEFAULT_MANUAL_URL, fetchCodexManual };
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("node:fs/promises");
|
||||
const path = require("node:path");
|
||||
|
||||
const DEFAULT_URL =
|
||||
"https://developers.openai.com/api/docs/guides/latest-model.md";
|
||||
const DEFAULT_BASE_URL = "https://developers.openai.com";
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = {
|
||||
source: process.env.LATEST_MODEL_URL || DEFAULT_URL,
|
||||
baseUrl: process.env.LATEST_MODEL_BASE_URL || DEFAULT_BASE_URL,
|
||||
};
|
||||
|
||||
for (let i = 2; i < argv.length; i += 1) {
|
||||
const arg = argv[i];
|
||||
if (arg === "--source" || arg === "--url") {
|
||||
args.source = argv[i + 1];
|
||||
i += 1;
|
||||
} else if (arg === "--base-url") {
|
||||
args.baseUrl = argv[i + 1];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
async function readSource(source) {
|
||||
if (source.startsWith("file://")) {
|
||||
return fs.readFile(new URL(source), "utf8");
|
||||
}
|
||||
|
||||
if (!/^https?:\/\//.test(source)) {
|
||||
return fs.readFile(path.resolve(source), "utf8");
|
||||
}
|
||||
|
||||
const response = await fetch(source, {
|
||||
headers: { accept: "text/markdown,text/plain,*/*" },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`failed to fetch ${source}: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.text();
|
||||
}
|
||||
|
||||
function parseIndentedInfo(lines, startIndex) {
|
||||
const info = {};
|
||||
|
||||
for (let i = startIndex + 1; i < lines.length; i += 1) {
|
||||
const line = lines[i];
|
||||
if (!line.trim()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = line.match(/^ {2}([A-Za-z][A-Za-z0-9_-]*):\s*(.+?)\s*$/);
|
||||
if (!match) {
|
||||
break;
|
||||
}
|
||||
|
||||
info[match[1]] = match[2].replace(/^["']|["']$/g, "");
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
function parseFlatInfo(block) {
|
||||
const info = {};
|
||||
|
||||
for (const line of block.split(/\r?\n/)) {
|
||||
const match = line.match(/^\s*([A-Za-z][A-Za-z0-9_-]*):\s*(.+?)\s*$/);
|
||||
if (match) {
|
||||
info[match[1]] = match[2].replace(/^["']|["']$/g, "");
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
function extractLatestModelInfo(markdown) {
|
||||
const lines = markdown.split(/\r?\n/);
|
||||
const latestModelInfoIndex = lines.findIndex((line) =>
|
||||
/^latestModelInfo:\s*$/.test(line)
|
||||
);
|
||||
|
||||
if (latestModelInfoIndex >= 0) {
|
||||
return parseIndentedInfo(lines, latestModelInfoIndex);
|
||||
}
|
||||
|
||||
const commentMatch = markdown.match(
|
||||
/<!--\s*latestModelInfo\s*\n([\s\S]*?)\n\s*-->/m
|
||||
);
|
||||
if (commentMatch) {
|
||||
return parseFlatInfo(commentMatch[1]);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function modelToSkillSlug(model) {
|
||||
return model.trim().replace(/\./g, "p");
|
||||
}
|
||||
|
||||
function absoluteUrl(baseUrl, value) {
|
||||
return new URL(value, baseUrl).toString();
|
||||
}
|
||||
|
||||
function normalizeInfo(info, baseUrl) {
|
||||
const model = info?.model?.trim();
|
||||
const migrationGuide = info?.migrationGuide?.trim();
|
||||
const promptingGuide = info?.promptingGuide?.trim();
|
||||
|
||||
if (!model || !migrationGuide || !promptingGuide) {
|
||||
throw new Error(
|
||||
"latestModelInfo must include model, migrationGuide, and promptingGuide"
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
model,
|
||||
modelSlug: modelToSkillSlug(model),
|
||||
migrationGuideUrl: absoluteUrl(baseUrl, migrationGuide),
|
||||
promptingGuideUrl: absoluteUrl(baseUrl, promptingGuide),
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { source, baseUrl } = parseArgs(process.argv);
|
||||
const markdown = await readSource(source);
|
||||
const info = extractLatestModelInfo(markdown);
|
||||
|
||||
if (!info) {
|
||||
throw new Error(`latestModelInfo block not found in ${source}`);
|
||||
}
|
||||
|
||||
process.stdout.write(
|
||||
`${JSON.stringify(normalizeInfo(info, baseUrl), null, 2)}\n`
|
||||
);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user