pi-openai-codex-compat 0.0.9 → 0.0.10-alpha.2

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.
Files changed (90) hide show
  1. package/APPLY_PATCH_INSTRUCTION_FEEDBACK.md +11 -55
  2. package/CHANGELOG.md +50 -0
  3. package/README.md +116 -38
  4. package/THIRD_PARTY_NOTICES.md +1 -27
  5. package/extensions/openai-codex-compat/apply-patch-diagnostics.ts +573 -0
  6. package/extensions/openai-codex-compat/apply-patch-diff-render.ts +20 -344
  7. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-contracts.ts +92 -0
  8. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-details-schema.ts +325 -0
  9. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-details.ts +227 -0
  10. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-errors.ts +60 -0
  11. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-executor.ts +583 -0
  12. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-failure-inspection.ts +493 -0
  13. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-feedback.ts +445 -0
  14. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-filesystem-inspection.ts +49 -0
  15. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-filesystem-model.ts +188 -0
  16. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-filesystem-mutations.ts +324 -0
  17. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-mutation-queue.ts +95 -0
  18. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-operation-semantics.ts +142 -0
  19. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-parser.ts +384 -0
  20. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-path-identity.ts +78 -0
  21. package/extensions/openai-codex-compat/apply-patch-engine/apply-patch-engine-semantic-planner.ts +1363 -0
  22. package/extensions/openai-codex-compat/apply-patch-engine.ts +81 -4572
  23. package/extensions/openai-codex-compat/apply-patch-matcher/apply-patch-matcher-contracts.ts +12 -0
  24. package/extensions/openai-codex-compat/apply-patch-matcher/apply-patch-matcher-line-matching.ts +123 -0
  25. package/extensions/openai-codex-compat/apply-patch-matcher/apply-patch-matcher-strict-content.ts +101 -0
  26. package/extensions/openai-codex-compat/apply-patch-matcher.ts +10 -1527
  27. package/extensions/openai-codex-compat/apply-patch-render.ts +14 -57
  28. package/extensions/openai-codex-compat/apply-patch.ts +87 -9
  29. package/extensions/openai-codex-compat/codex-cache-diagnostics.ts +24 -24
  30. package/extensions/openai-codex-compat/codex-identifiers.ts +8 -0
  31. package/extensions/openai-codex-compat/codex-installation.ts +3 -10
  32. package/extensions/openai-codex-compat/codex-metadata.ts +49 -28
  33. package/extensions/openai-codex-compat/codex-protocol.ts +260 -161
  34. package/extensions/openai-codex-compat/codex-provider/codex-provider-contracts.ts +108 -0
  35. package/extensions/openai-codex-compat/codex-provider/codex-provider-history.ts +106 -0
  36. package/extensions/openai-codex-compat/codex-provider/codex-provider-response-attempts.ts +408 -0
  37. package/extensions/openai-codex-compat/codex-provider/codex-provider-runtime.ts +1281 -0
  38. package/extensions/openai-codex-compat/codex-provider.ts +11 -1651
  39. package/extensions/openai-codex-compat/codex-stream.ts +76 -77
  40. package/extensions/openai-codex-compat/codex-thread-lineage.ts +83 -37
  41. package/extensions/openai-codex-compat/codex-tool-surface.ts +18 -8
  42. package/extensions/openai-codex-compat/codex-transport/codex-transport-contracts.ts +262 -0
  43. package/extensions/openai-codex-compat/codex-transport/codex-transport-diagnostics.ts +263 -0
  44. package/extensions/openai-codex-compat/codex-transport/codex-transport-errors.ts +172 -0
  45. package/extensions/openai-codex-compat/codex-transport/codex-transport-events.ts +68 -0
  46. package/extensions/openai-codex-compat/codex-transport/codex-transport-request-headers.ts +315 -0
  47. package/extensions/openai-codex-compat/codex-transport/codex-transport-retry.ts +124 -0
  48. package/extensions/openai-codex-compat/codex-transport/codex-transport-sse-stream.ts +214 -0
  49. package/extensions/openai-codex-compat/codex-transport/codex-transport-turn-state.ts +23 -0
  50. package/extensions/openai-codex-compat/codex-transport/codex-transport-websocket-continuation.ts +107 -0
  51. package/extensions/openai-codex-compat/codex-transport/codex-transport-websocket-pool.ts +257 -0
  52. package/extensions/openai-codex-compat/codex-transport/codex-transport-websocket-stream.ts +320 -0
  53. package/extensions/openai-codex-compat/codex-transport.ts +251 -2074
  54. package/extensions/openai-codex-compat/compaction-checkpoint.ts +169 -78
  55. package/extensions/openai-codex-compat/config-context.ts +10 -0
  56. package/extensions/openai-codex-compat/config.ts +124 -88
  57. package/extensions/openai-codex-compat/error-from-thrown.ts +3 -0
  58. package/extensions/openai-codex-compat/footer.ts +87 -18
  59. package/extensions/openai-codex-compat/image-generation-render.ts +31 -33
  60. package/extensions/openai-codex-compat/image-generation-schema.ts +5 -9
  61. package/extensions/openai-codex-compat/image-generation.ts +81 -51
  62. package/extensions/openai-codex-compat/index.ts +23 -11
  63. package/extensions/openai-codex-compat/model-context.ts +20 -0
  64. package/extensions/openai-codex-compat/model-policy.ts +77 -12
  65. package/extensions/openai-codex-compat/namespaced-tools.ts +2 -1
  66. package/extensions/openai-codex-compat/native-history.ts +55 -55
  67. package/extensions/openai-codex-compat/output-limit-continuation.ts +89 -21
  68. package/extensions/openai-codex-compat/remote-compaction.ts +151 -58
  69. package/extensions/openai-codex-compat/request-options.ts +29 -22
  70. package/extensions/openai-codex-compat/required-value.ts +6 -0
  71. package/extensions/openai-codex-compat/responses-event-schema.ts +7 -0
  72. package/extensions/openai-codex-compat/responses-item-schema.ts +461 -0
  73. package/extensions/openai-codex-compat/responses-lite.ts +16 -16
  74. package/extensions/openai-codex-compat/responses-replay.ts +18 -4
  75. package/extensions/openai-codex-compat/responses-tool-schema.ts +92 -0
  76. package/extensions/openai-codex-compat/settings-pane.ts +120 -45
  77. package/extensions/openai-codex-compat/tool-definition-contract.ts +28 -0
  78. package/extensions/openai-codex-compat/tool-runtime.ts +27 -13
  79. package/extensions/openai-codex-compat/tools.ts +21 -12
  80. package/extensions/openai-codex-compat/value-contracts.ts +37 -0
  81. package/extensions/openai-codex-compat/vendor/pi-ai/README.md +6 -1
  82. package/extensions/openai-codex-compat/vendor/pi-ai/openai-responses-serialization.ts +117 -73
  83. package/extensions/openai-codex-compat/web-run-output.ts +22 -13
  84. package/extensions/openai-codex-compat/web-run-render.ts +54 -40
  85. package/extensions/openai-codex-compat/web-run-schema.ts +5 -55
  86. package/extensions/openai-codex-compat/web-run.ts +83 -39
  87. package/package.json +8 -11
  88. package/LICENSES/tree-sitter-wasms-MIT.txt +0 -21
  89. package/LICENSES/web-tree-sitter-MIT.txt +0 -21
  90. package/extensions/openai-codex-compat/provider-error.ts +0 -79
@@ -17,8 +17,8 @@ Feedback must:
17
17
  1. retain the aggregate changed-file summary;
18
18
  2. when an instruction ledger is needed, report every instruction without a
19
19
  model-facing limit;
20
- 3. attribute filesystem effects, errors, and matching evidence to the
21
- instruction that produced them;
20
+ 3. attribute filesystem effects and errors to the instruction that produced
21
+ them;
22
22
  4. report failed and not-run instructions;
23
23
  5. use concise, simplified technical English;
24
24
  6. report deterministic facts rather than speculative outcomes; and
@@ -134,8 +134,7 @@ Add a short clause only for:
134
134
  - a failure;
135
135
  - a non-obvious externally visible filesystem effect;
136
136
  - a partial effect;
137
- - a final state that is not verified; or
138
- - concise matcher evidence.
137
+ - a final state that is not verified.
139
138
 
140
139
  Do not include:
141
140
 
@@ -143,7 +142,6 @@ Do not include:
143
142
  - a diff-availability warning;
144
143
  - verbose proof sections;
145
144
  - a duplicated raw error section;
146
- - a detached matcher section; or
147
145
  - prose that merely restates an ordinary successful operation.
148
146
 
149
147
  ## Terminology
@@ -227,7 +225,6 @@ Each instruction result stores:
227
225
  - completed externally visible filesystem effects;
228
226
  - relevant final path states;
229
227
  - an optional error;
230
- - optional matcher evidence; and
231
228
  - related instruction numbers.
232
229
 
233
230
  The operation label is sufficient for ordinary successful effects. Explicit
@@ -346,37 +343,17 @@ Do not tell the model that previous content was unreadable, a diff is
346
343
  unavailable, history is incomplete, or the result is inexact. Diff
347
344
  availability is a TUI/history concern, not an operation result.
348
345
 
349
- ## Matcher feedback
350
-
351
- Matcher feedback belongs to the failed update instruction. Do not emit a
352
- detached `Matcher diagnostics:` section or repeat old/replacement patch text.
353
-
354
- Examples:
346
+ ## Matching failures
355
347
 
356
- ```text
357
- 3. [FAILED] Update file.ts - Old content was not found. Read the current file and use apply_patch again with updated instructions if needed.
358
- ```
348
+ A strict matching failure belongs to the failed update instruction. Do not
349
+ emit a detached matcher-diagnostics section or repeat old/replacement patch
350
+ text:
359
351
 
360
352
  ```text
361
- 3. [FAILED] Update file.ts - The requested changes match in reverse source-file order at lines 10-12 and lines 30-32. Use apply_patch again with the requested changes in source-file order if needed.
353
+ 3. [FAILED] Update file.ts - Old content was not found.
362
354
  ```
363
355
 
364
- ```text
365
- 3. [FAILED] Update file.ts - Matching locations at lines 10-12 and lines 40-42 produce different results. Use apply_patch again with more specific surrounding context or smaller changes if needed.
366
- ```
367
-
368
- ```text
369
- 3. [FAILED] Update file.ts - More than 256 possible ways to apply the requested changes were found. Use apply_patch again with more specific surrounding context or smaller changes if needed.
370
- ```
371
-
372
- ```text
373
- 3. [FAILED] Update file.ts - Requested replacement found at lines 40-44, but old content was not found. Inspect the reported lines and use apply_patch again with updated instructions if needed.
374
- ```
375
-
376
- The 64-location limit, different-result ambiguity, and 256-way limit use the
377
- same guidance because each requires more specific surrounding context or
378
- smaller requested changes. Reverse-order and overlap failures instead tell the
379
- model to reorder or separate the requested changes.
356
+ Missing `@@` anchors analogously report `Context was not found.`.
380
357
 
381
358
  ## Not-run results
382
359
 
@@ -457,7 +434,6 @@ Expanded rendering nests these details beneath the relevant instruction:
457
434
  - applied textual diffs;
458
435
  - non-obvious filesystem effects;
459
436
  - final-state verification;
460
- - concise matcher locations; and
461
437
  - useful system-error details.
462
438
 
463
439
  Partial effects are not rendered as detached successful operations. Failed
@@ -483,7 +459,6 @@ type InstructionResult = {
483
459
  effects: InstructionEffect[];
484
460
  finalStates: FinalPathState[];
485
461
  error?: InstructionError;
486
- matching?: MatchingEvidence;
487
462
  relatedInstructions?: number[];
488
463
  };
489
464
  ```
@@ -512,18 +487,6 @@ Only presentation differs:
512
487
 
513
488
  Semantic wording and facts remain shared.
514
489
 
515
- ## Matcher candidate deduplication
516
-
517
- Before applying candidate and mapping limits:
518
-
519
- 1. canonicalize candidates by complete byte-edit effect;
520
- 2. remove byte-identical duplicate candidates;
521
- 3. retain every semantically distinct candidate; and
522
- 4. do not rank candidates or use heuristic preference.
523
-
524
- This prevents duplicate line-level and structural candidates from consuming
525
- the exhaustive mapping bound.
526
-
527
490
  ## Required tests
528
491
 
529
492
  ### Completeness
@@ -552,7 +515,6 @@ Generated model and TUI feedback does not contain:
552
515
  - `installed`
553
516
  - `dead`
554
517
  - `dominated`
555
- - `Matcher diagnostics`
556
518
  - the heading `Instructions:`
557
519
 
558
520
  When the conditional ledger is present, its heading is
@@ -583,8 +545,8 @@ Cover:
583
545
  - temporary entry remains without a false no-change statement; and
584
546
  - post-operation verification failure.
585
547
 
586
- Every formatter-matcher failure reason is covered with its direct retry
587
- guidance.
548
+ Strict mismatch coverage verifies the source is unchanged and the original
549
+ context or expected-lines error is reported.
588
550
 
589
551
  ### No patch-content repetition
590
552
 
@@ -602,16 +564,10 @@ With `applyPatchDebug` enabled:
602
564
  - changing the setting updates existing result components; and
603
565
  - partial previews remain unchanged.
604
566
 
605
- ### Matcher deduplication
606
-
607
- A multi-group formatter-recovery fixture proves duplicate candidates do not
608
- consume the mapping limit.
609
-
610
567
  ## Documentation
611
568
 
612
569
  Implementation changes must also update:
613
570
 
614
571
  - `APPLY_PATCH_SEMANTIC_OPERATIONS.md`
615
- - `APPLY_PATCH_REMAINING_WORK.md`
616
572
  - `README.md`
617
573
  - `CHANGELOG.md`
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Added
6
+
7
+ - Show the current Pi session ID on the compatibility footer's first line.
8
+ - Add default-off, failure-only `apply_patch` diagnostics capture with
9
+ pre-execution text snapshots and binary metadata for every instruction in a
10
+ failed patch, runtime and filesystem identity metadata, nested error causes,
11
+ patch outcomes, and Pi/provider trace identifiers linked from tool-result
12
+ details.
13
+
14
+ ### Fixed
15
+
16
+ - Preserve regular-file permission modes across sequential `apply_patch`
17
+ replacements and state-changing moves, including files created by earlier
18
+ instructions in the same patch.
19
+ - Resolve descendants through symlink parents established by earlier
20
+ instructions, keeping subsequent aliased operations in one virtual
21
+ filesystem state.
22
+ - Resolve relative symlink targets from the canonical source or moved
23
+ destination directory when a parent path is itself a symlink.
24
+ - Verify the complete final byte buffer after `apply_patch` adds and text
25
+ updates, so requested bytes appearing in a duplicate or unrelated region
26
+ cannot satisfy the result postcondition.
27
+ - Classify repeated identical `apply_patch` adds from source-ordered virtual
28
+ content and exact spelling, avoiding redundant replacements after earlier
29
+ adds or moves while preserving case, Unicode, and symlink-parent identity.
30
+ - Use actual or planned directory-entry spelling when proving dead
31
+ `apply_patch` operations and classifying same-entry moves on case-insensitive
32
+ or Unicode-normalizing filesystems.
33
+ - Validate supplied identity and context chunks before `apply_patch` moves while preserving chunkless opaque moves and successful symlink and hard-link topology.
34
+ - Remove formatter-tolerant `apply_patch` matching permanently and rely exclusively on the official Codex-compatible exact, trailing-trim, full-trim, and Unicode matcher.
35
+ - Treat streamed Codex misalignment-policy violations as terminal without retrying and preserve the provider's error message.
36
+ - Preserve unexpected parser, matcher, and asynchronous transport failures instead of replacing or detaching them.
37
+ - Recover expired 60-minute Codex WebSockets in the provider response loop, retaining committed items, discarding provisional output, and waiting for Pi to record completed tool outputs before continuing.
38
+ - Validate complete apply-patch result details against schema-derived contracts before rendering, including integer metadata and nested instruction relationships.
39
+ - Distinguish an unavailable Pi compaction append capability from a missing percentage-compaction retention boundary.
40
+ - Validate supported Responses input, completed-output, content, and tool-definition variants with closed schema-derived unions, failing closed on unknown or malformed item types while preserving additional fields on known variants.
41
+
42
+ ### Changed
43
+
44
+ - Align deferred tool loading with Pi 0.84.3, preferring message-anchored
45
+ additional tools on capable Codex models while retaining tool-search and
46
+ top-level fallbacks.
47
+ - Simplify `apply_patch` for its queued single-writer operating model: retain
48
+ Pi's mutation queue, remove the extension-local alias queue and
49
+ preflight-to-execution drift machinery, use direct writes for in-place text
50
+ updates, and preserve source-ordered no-change checkpoints without
51
+ filesystem revalidation.
52
+ - Adopt the shared 2h2d Oxlint policy and exact supported Oxlint and Oxfmt versions.
53
+ - Run isolated test files across four workers, bypass unasserted wall-clock response-retry waits in integration coverage, and assert the retry-delay calculation directly.
54
+
5
55
  ## 0.0.9 - 2026-08-16
6
56
 
7
57
  ### Fixed
package/README.md CHANGED
@@ -7,13 +7,14 @@ OpenAI Codex compatibility for [Pi](https://github.com/earendil-works/pi-mono),
7
7
  - **Request-level fast mode**: keeps the canonical `openai-codex` provider id and models selected while adding `service_tier: "priority"` at the request boundary.
8
8
  - **Native compaction**: uses Codex `remote_compaction_v2` for `/compact`, Pi threshold compaction, context-overflow recovery, and an optional percentage threshold.
9
9
  - **Codex `apply_patch`**: provides an optional patch tool with the Codex grammar, parser, fuzzy matcher, overwrite semantics, filesystem behavior, model-facing result format, structured history, and diff-oriented TUI rendering. Pi sends it as an OpenAI custom grammar tool when the model supports that protocol and as a normal function tool otherwise.
10
+ - **Opt-in patch diagnostics**: records failed `apply_patch` requests with pre-execution text snapshots or binary metadata for every instruction, outcomes, and Pi/Codex identifiers.
10
11
  - **Standalone image generation**: exposes Pi's dotted `image_gen.imagegen` tool as a native Responses namespace and executes generation or edits through the Codex Images endpoints.
11
12
  - **Standalone web search**: exposes Pi's dotted `web.run` tool as a native Responses namespace and executes search and browsing through Codex `alpha/search`.
12
13
  - **Dedicated Codex tool UI**: renders `apply_patch`, `image_gen.imagegen`, and `web.run` on a shared configurable surface with compact summaries and `Ctrl+O` expansion.
13
14
  - **Hosted web-search fallback**: injects native `web_search` only when `web.run` is inactive, with cached, indexed, or live modes.
14
15
  - **Native request controls**: configures Responses API text verbosity, reasoning summaries, and GPT-5.6 standard/pro reasoning mode.
15
16
  - **Session-local settings pane**: `/codex-settings` changes every compatibility setting for the current session; `Enter` persists and closes, `Escape` discards unsaved changes and closes, and `Ctrl+S` persists without closing.
16
- - **Compact footer indicators**: non-default Codex request modes are appended to the model side of Pi's normal second footer line.
17
+ - **Session-aware footer**: shows the current Pi session ID on the first line and appends non-default Codex request modes to the model side of Pi's normal second line.
17
18
 
18
19
  Pi provides the Codex OAuth flow and model catalog. At session start, this package overrides the built-in `openai-codex` runtime under the same provider id so ordinary responses and remote compaction share one transport, parser, native-history store, and sticky WebSocket session.
19
20
 
@@ -31,7 +32,7 @@ Authenticate through Pi if needed:
31
32
 
32
33
  ## Compatibility baseline and differences
33
34
 
34
- The compatibility baseline is official Codex CLI `0.146.0`, released July 29, 2026. Upstream `main` at commit `0bdce9f424eb9b39d7b3a8811742d10b6fbf8d54` was also inspected on August 7, 2026, including post-release routing and default-tool namespace changes. Current upstream, rather than the older installed CLI, is authoritative where they differ: commit `f21dc46388` replaced direct Lite function/custom declarations with one canonical `functions` namespace. This section is the package's explicit compatibility contract: it distinguishes close protocol adaptations from deliberate Pi behavior, configurable defaults, known gaps, and unsupported Codex runtimes. See the [Responses Lite compatibility report](RESPONSES_LITE_COMPATIBILITY.md) and [Codex caching and transport comparison](CODEX_CACHE_RESEARCH.md) for source revisions, request-path findings, and live cache trajectories.
35
+ The compatibility baseline is official Codex CLI `0.149.0`, released August 20, 2026, at commit `758ef40f50c1a458425c7cfbf1eb12cbc07af0b0`. It retains the `0.147.0` Responses Lite contract that groups direct function and custom declarations into one canonical `functions` namespace for namespace-capable providers. The `0.148.0`–`0.149.0` review adopted typed misalignment-policy failures while recording official unbounded connection recovery as an intentional bounded-transport deviation. The [official release compatibility log](OFFICIAL_CODEX_CLI_RELEASES.md) is the canonical release-by-release record of protocol and `apply_patch` alignment, intentional deviations, and excluded runtimes. This section is the package's user-facing compatibility contract. See the [Responses Lite compatibility report](RESPONSES_LITE_COMPATIBILITY.md) and [Codex caching and transport comparison](CODEX_CACHE_RESEARCH.md) for detailed request-path findings and live cache trajectories.
35
36
 
36
37
  ### Configurable defaults that differ from Codex
37
38
 
@@ -43,6 +44,7 @@ The compatibility baseline is official Codex CLI `0.146.0`, released July 29, 20
43
44
  | Hosted web search | Disabled by default; when enabled, injected only for ordinary Responses while `web.run` is inactive. Responses Lite omits hosted tools. | Omitted for `gpt-5.6-sol` while standalone `web.run` is available; otherwise defaults to cached mode when hosted search is supported. | `webRun` and `webSearch`: `disabled`, `cached`, `indexed`, or `live`. |
44
45
  | Coding mutation tools | Enables `apply_patch` and suppresses Pi's active `edit` and `write` tools. | Chooses its tool surface from model metadata and runtime capabilities; there are no Pi `edit` or `write` tools to suppress. | `applyPatch`: boolean. |
45
46
  | `apply_patch` debug output | Disabled; collapsed results show the normal visual summary and instruction rows. | Not applicable to Pi's tool-result renderer. | `applyPatchDebug`: boolean. |
47
+ | `apply_patch` diagnostics capture | Disabled; no separate request or filesystem snapshot artifacts are retained. | Codex owns its rollout diagnostics rather than writing this package's artifact format. | `applyPatchDiagnostics`: boolean. |
46
48
  | Codex tool background | Uses a subtle theme-derived surface for extension-owned Codex tools. | Uses Codex's own TUI activity cells rather than Pi tool rows. | `toolBackground`: `subtle`, `status`, or `none`. |
47
49
  | Auto-compaction trigger | Relies on Pi's reserve-token threshold unless a percentage is configured. | Tracks Codex's model/token-budget state before and between sampling steps. | `autoCompactAtPercent`: percentage or unset. Mid-response percentage boundaries use Pi's bounded compact-and-continue lifecycle, so Pi auto-compaction must remain enabled. |
48
50
  | Fast mode | Uses the normal tier. | Uses the configured Codex service tier. | `fastMode`: boolean; `true` requests the priority tier. |
@@ -63,6 +65,7 @@ The compatibility baseline is official Codex CLI `0.146.0`, released July 29, 20
63
65
  | Cache preparation | Before the first cache-enabled WebSocket turn, the package prewarms only the stable instruction/tool prefix: ordinary Responses uses empty `input`, while Responses Lite uses `additional_tools` plus the developer instructions. The first generated request then contributes only dynamic conversation input to the continuation. No explicit prompt-cache breakpoints are added. |
64
66
  | Mid-turn compaction | Provider-boundary percentage compaction preserves a successful `end_turn:false` prefix as its own Pi assistant message, installs a checkpoint, and continues without synthetic model input. Pi threshold compaction normally runs after the agent response; after Codex output-token truncation, the extension queues a hidden continuation so threshold compaction completes before sampling resumes. Official Codex owns this sampling and compaction loop directly. |
65
67
  | Provider-owned follow-up | Completed responses with `end_turn: false` continue immediately from completed native output without synthetic user input. Retryable `response.failed` and all `response.incomplete` events are resampled with the official five-retry stream budget, preserving completed output and cumulative usage while excluding unfinished attempt content. A `max_output_tokens` response that exhausts this budget still becomes Pi `stopReason: "length"` and uses the extension's unbounded host-level continuation recovery. |
68
+ | Transport recovery | WebSocket failures before model-visible output receive five fresh-connection retries before sticky SSE fallback; SSE transport failures receive five retries. Official Codex `0.149.0` separately retries sampling connection-establishment failures indefinitely with delays capped at 60 seconds. The package remains bounded because Fetch does not expose Reqwest's narrower connection-error category, and a phase-only approximation could indefinitely repeat requests that reached the server. |
66
69
  | Compaction lifecycle events | Pre-turn percentage compaction writes through Pi's mutable session manager and cannot emit Pi's internal `session_compact` event through the public extension API. Mid-response percentage boundaries and manual, threshold, or overflow compactions initiated by Pi emit the normal lifecycle. |
67
70
  | Header hooks | An internal percentage-compaction request reuses the already transformed provider headers. It cannot independently rerun Pi's `before_provider_headers` hook. |
68
71
  | Native retained context | Deliberately differs from current Codex. The package retains recent user/developer/system messages under the 64k budget before the opaque compaction item. Current Codex applies a second installed-history filter that drops developer/system wrappers and non-real-user messages, can retain eligible structured agent commentary, and trims oversized function outputs before compaction. Pi keeps its existing checkpoint shape by design. |
@@ -164,7 +167,7 @@ A trusted project can override it at:
164
167
 
165
168
  Each session inherits the effective file-backed settings. Open `/codex-settings` to make immediate session-local changes. Press `Enter` to persist and close, `Escape` to discard unsaved changes and close, or `Ctrl+S` to persist without closing. The global file is the normal save target, while an existing trusted project override remains the target for that project. After `Ctrl+S`, later unsaved changes can still be discarded back to the values from that save.
166
169
 
167
- The effective settings are printed once when a TUI session starts. The footer shows `fast` and `pro` only when enabled, and shows text verbosity or reasoning summary only when they differ from their defaults.
170
+ The effective settings are printed once when a TUI session starts. The footer shows the current Pi session ID alongside the working directory and optional session name. It shows `fast` and `pro` only when enabled, and shows text verbosity or reasoning summary only when they differ from their defaults.
168
171
 
169
172
  Example:
170
173
 
@@ -175,6 +178,7 @@ Example:
175
178
  "toolBackground": "subtle",
176
179
  "applyPatch": true,
177
180
  "applyPatchDebug": false,
181
+ "applyPatchDiagnostics": false,
178
182
  "imageGeneration": true,
179
183
  "imageDetail": "auto",
180
184
  "webRun": false,
@@ -188,41 +192,43 @@ Example:
188
192
 
189
193
  Defaults:
190
194
 
191
- | Setting | Values | Default | Behavior |
192
- | ---------------------- | ---------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
- | `fastMode` | boolean | `false` | Adds `service_tier: "priority"` to requests while retaining the current `openai-codex` provider and model. |
194
- | `responsesLite` | boolean | `false` | Uses Codex's Responses Lite input envelope on supported GPT-5.6 models when enabled. By default, those models use ordinary Responses instructions and tools. |
195
- | `toolBackground` | `subtle`, `status`, `none` | `subtle` | Controls the shared self-rendered background for `apply_patch`, `image_gen.imagegen`, and `web.run`. `status` uses Pi's pending/success/error backgrounds; `none` keeps the custom layout transparent. |
196
- | `applyPatch` | boolean | `true` | On selected `openai-codex` models, uses the extension's `apply_patch` tool instead of Pi's active `edit` and `write` tools. Other providers always use their normal Pi tool set. |
197
- | `applyPatchDebug` | boolean | `false` | Shows the exact model-facing tool result while a completed `apply_patch` result is collapsed. Expanded results continue to show the normal visual summary and complete diffs. |
198
- | `imageGeneration` | boolean | `true` | Enables the extension-owned `image_gen.imagegen` tool on selected `openai-codex` models. |
199
- | `imageDetail` | `auto`, `low`, `high`, `original` | `auto` | Sets `input_image.detail` when an image tool result is sent back to the model. It does not change `gpt-image-2` generation quality. |
200
- | `webRun` | boolean | `false` | Enables the extension-owned `web.run` tool on selected `openai-codex` models. When active, it replaces hosted `web_search` in the Responses tool list. |
201
- | `autoCompactAtPercent` | number greater than `0` and at most `100`, or `null` | unset | Adds provider-boundary compaction independently of Pi's normal reserve-token threshold. Mid-response boundaries require Pi auto-compaction. A project value of `null` disables a global percentage threshold. |
202
- | `webSearch` | `disabled`, `cached`, `indexed`, `live` | `disabled` | Controls hosted search and standalone-search external access. `disabled` removes hosted search but leaves an independently enabled `web.run` in cached-only mode; `indexed` prefers indexed content; `live` permits live external access. |
203
- | `textVerbosity` | `low`, `medium`, `high` | `low` | Sets Responses API `text.verbosity`. |
204
- | `reasoningSummary` | `auto`, `concise`, `detailed`, `off` | `auto` | Sets `reasoning.summary` when reasoning is enabled; `off` omits the summary parameter. |
205
- | `reasoningMode` | `standard`, `pro` | `standard` | Controls GPT-5.6 execution mode independently of Pi's reasoning-effort control. The default omits `reasoning.mode`; `pro` sends `reasoning.mode: "pro"`. |
195
+ | Setting | Values | Default | Behavior |
196
+ | ----------------------- | ---------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
197
+ | `fastMode` | boolean | `false` | Adds `service_tier: "priority"` to requests while retaining the current `openai-codex` provider and model. |
198
+ | `responsesLite` | boolean | `false` | Uses Codex's Responses Lite input envelope on supported GPT-5.6 models when enabled. By default, those models use ordinary Responses instructions and tools. |
199
+ | `toolBackground` | `subtle`, `status`, `none` | `subtle` | Controls the shared self-rendered background for `apply_patch`, `image_gen.imagegen`, and `web.run`. `status` uses Pi's pending/success/error backgrounds; `none` keeps the custom layout transparent. |
200
+ | `applyPatch` | boolean | `true` | On selected `openai-codex` models, uses the extension's `apply_patch` tool instead of Pi's active `edit` and `write` tools. Other providers always use their normal Pi tool set. |
201
+ | `applyPatchDebug` | boolean | `false` | Shows the exact model-facing tool result while a completed `apply_patch` result is collapsed. Expanded results continue to show the normal visual summary and complete diffs. |
202
+ | `applyPatchDiagnostics` | boolean | `false` | Persists failed patch requests with pre-execution text snapshots or binary metadata for every instruction, outcomes, and trace identifiers. See [`apply_patch`](#apply_patch) for storage and sensitivity details. |
203
+ | `imageGeneration` | boolean | `true` | Enables the extension-owned `image_gen.imagegen` tool on selected `openai-codex` models. |
204
+ | `imageDetail` | `auto`, `low`, `high`, `original` | `auto` | Sets `input_image.detail` when an image tool result is sent back to the model. It does not change `gpt-image-2` generation quality. |
205
+ | `webRun` | boolean | `false` | Enables the extension-owned `web.run` tool on selected `openai-codex` models. When active, it replaces hosted `web_search` in the Responses tool list. |
206
+ | `autoCompactAtPercent` | number greater than `0` and at most `100`, or `null` | unset | Adds provider-boundary compaction independently of Pi's normal reserve-token threshold. Mid-response boundaries require Pi auto-compaction. A project value of `null` disables a global percentage threshold. |
207
+ | `webSearch` | `disabled`, `cached`, `indexed`, `live` | `disabled` | Controls hosted search and standalone-search external access. `disabled` removes hosted search but leaves an independently enabled `web.run` in cached-only mode; `indexed` prefers indexed content; `live` permits live external access. |
208
+ | `textVerbosity` | `low`, `medium`, `high` | `low` | Sets Responses API `text.verbosity`. |
209
+ | `reasoningSummary` | `auto`, `concise`, `detailed`, `off` | `auto` | Sets `reasoning.summary` when reasoning is enabled; `off` omits the summary parameter. |
210
+ | `reasoningMode` | `standard`, `pro` | `standard` | Controls GPT-5.6 execution mode independently of Pi's reasoning-effort control. The default omits `reasoning.mode`; `pro` sends `reasoning.mode: "pro"`. |
206
211
 
207
212
  Invalid JSON setting values are ignored and invalid JSON does not prevent Pi from starting. The settings pane never writes on ordinary changes, refuses to overwrite invalid JSON when `Enter` or `Ctrl+S` attempts to save, and retains unknown keys when saving. Project configuration is read only when the project is trusted.
208
213
 
209
214
  Every setting can also be overridden for one Pi process with an environment variable:
210
215
 
211
- | Setting | Environment variable |
212
- | ---------------------- | ------------------------------------------------ |
213
- | `fastMode` | `PI_OPENAI_CODEX_COMPAT_FAST_MODE` |
214
- | `responsesLite` | `PI_OPENAI_CODEX_COMPAT_RESPONSES_LITE` |
215
- | `toolBackground` | `PI_OPENAI_CODEX_COMPAT_TOOL_BACKGROUND` |
216
- | `applyPatch` | `PI_OPENAI_CODEX_COMPAT_APPLY_PATCH` |
217
- | `applyPatchDebug` | `PI_OPENAI_CODEX_COMPAT_APPLY_PATCH_DEBUG` |
218
- | `imageGeneration` | `PI_OPENAI_CODEX_COMPAT_IMAGE_GENERATION` |
219
- | `imageDetail` | `PI_OPENAI_CODEX_COMPAT_IMAGE_DETAIL` |
220
- | `webRun` | `PI_OPENAI_CODEX_COMPAT_WEB_RUN` |
221
- | `autoCompactAtPercent` | `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT` |
222
- | `webSearch` | `PI_OPENAI_CODEX_COMPAT_WEB_SEARCH_MODE` |
223
- | `textVerbosity` | `PI_OPENAI_CODEX_COMPAT_TEXT_VERBOSITY` |
224
- | `reasoningSummary` | `PI_OPENAI_CODEX_COMPAT_REASONING_SUMMARY` |
225
- | `reasoningMode` | `PI_OPENAI_CODEX_COMPAT_REASONING_MODE` |
216
+ | Setting | Environment variable |
217
+ | ----------------------- | ------------------------------------------------ |
218
+ | `fastMode` | `PI_OPENAI_CODEX_COMPAT_FAST_MODE` |
219
+ | `responsesLite` | `PI_OPENAI_CODEX_COMPAT_RESPONSES_LITE` |
220
+ | `toolBackground` | `PI_OPENAI_CODEX_COMPAT_TOOL_BACKGROUND` |
221
+ | `applyPatch` | `PI_OPENAI_CODEX_COMPAT_APPLY_PATCH` |
222
+ | `applyPatchDebug` | `PI_OPENAI_CODEX_COMPAT_APPLY_PATCH_DEBUG` |
223
+ | `applyPatchDiagnostics` | `PI_OPENAI_CODEX_COMPAT_APPLY_PATCH_DIAGNOSTICS` |
224
+ | `imageGeneration` | `PI_OPENAI_CODEX_COMPAT_IMAGE_GENERATION` |
225
+ | `imageDetail` | `PI_OPENAI_CODEX_COMPAT_IMAGE_DETAIL` |
226
+ | `webRun` | `PI_OPENAI_CODEX_COMPAT_WEB_RUN` |
227
+ | `autoCompactAtPercent` | `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT` |
228
+ | `webSearch` | `PI_OPENAI_CODEX_COMPAT_WEB_SEARCH_MODE` |
229
+ | `textVerbosity` | `PI_OPENAI_CODEX_COMPAT_TEXT_VERBOSITY` |
230
+ | `reasoningSummary` | `PI_OPENAI_CODEX_COMPAT_REASONING_SUMMARY` |
231
+ | `reasoningMode` | `PI_OPENAI_CODEX_COMPAT_REASONING_MODE` |
226
232
 
227
233
  Environment variables have the highest precedence: defaults < global JSON < trusted-project JSON < environment. Boolean values accept `true`/`false`, `1`/`0`, `on`/`off`, or `enabled`/`disabled`. Other settings use the values in the defaults table; `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT=off` and `PI_OPENAI_CODEX_COMPAT_AUTO_COMPACT_AT_PERCENT=default` explicitly select Pi's default compaction lifecycle.
228
234
 
@@ -297,10 +303,17 @@ Compatibility behavior:
297
303
  - `*** Add File` overwrites an existing file, matching Codex.
298
304
  - `*** Move to` overwrites an existing destination, matching Codex.
299
305
  - Hunk matching retries exact text, trailing-whitespace-insensitive text, fully trimmed text, and Codex's Unicode punctuation normalization.
300
- - After strict matching fails, uniquely determined formatter-only line reflow can recover through exact Tree-sitter tokens for JavaScript, JSX, TypeScript, TSX, Python, Go, Java, and Scala. Requested replacement lines remain opaque and exact.
301
- - Markdown recovery is limited to exact-cell tables and supported code inside typed fences. Plain prose reflow, optional punctuation differences, single-token structural recovery, and partial-line structural recovery reject.
306
+ - Matching stops after the official Codex-compatible line matcher. There is no Tree-sitter, Markdown-table, code-fence, formatter-reflow, candidate-ranking, or output-equivalence fallback.
307
+ - Move identity and context chunks must match before the entry is moved; chunkless moves remain byte-opaque.
302
308
  - The parser accepts Codex's lenient marker whitespace, blank update-context lines, and direct heredoc wrappers.
303
309
  - Empty and identity updates, identical adds, absent deletes, self-moves, and same-patch fulfilled moves succeed with concise `NO CHANGE` results. Inapplicable operations are `SKIPPED` only when later operations deterministically make every effect unobservable.
310
+ - Repeated identical adds use source-ordered virtual content and exact
311
+ spelling, so an earlier add or move can satisfy a later add without a
312
+ redundant replacement.
313
+ - State-dependent `NO CHANGE` results retain source-ordered execution
314
+ checkpoints without rereading the filesystem. A checkpoint after an earlier
315
+ failure is `NOT RUN`; empty updates, identity updates without moves, and
316
+ chunkless lexical self-moves remain unconditional.
304
317
  - Model-facing results retain the aggregate A/M/D summary. When any instruction is not applied or an applied instruction has feedback, they list every source-ordered instruction under `Patch instruction results:` as `N. [STATUS] operation`, without an instruction limit; ordinary all-applied results omit the ledger.
305
318
  - Combined text updates and moves are labeled `Update & Move`; move-only operations remain `Move`.
306
319
  - Replacement feedback always identifies the verified previous and resulting entry types. Symlink feedback also uses the raw target pathname stored in the symlink.
@@ -308,19 +321,84 @@ Compatibility behavior:
308
321
  - Opaque moves and symlink deletions use path-only history, so binary bytes and link-target bytes are not serialized as textual deletions.
309
322
  - The TUI retains Codex-style changed-file summaries and uses the same conditional instruction ledger; when present, `Ctrl+O` nests complete diffs beneath the instruction that produced them.
310
323
  - With `applyPatchDebug` enabled, the tool title becomes `apply_patch (debug)` and a completed collapsed result shows the exact text returned to the model without an extra renderer-only heading; expanding it with `Ctrl+O` still shows the normal visual summary and complete diffs.
311
- - Failed instruction feedback colocates its error, completed effects, final path states, and concise matcher evidence without repeating patch text or using speculative language. Matcher failures include direct guidance for retrying with updated, source-ordered, non-overlapping, or more specific instructions.
324
+ - Failed instruction feedback colocates its error, completed effects, and final path states without repeating patch text or using speculative language. Matching failures report the original context or expected-lines mismatch.
325
+
326
+ With `applyPatchDiagnostics` enabled, the extension prepares pre-execution
327
+ snapshots in memory for each invocation. A successful invocation discards that
328
+ prepared data and writes no diagnostic artifacts or tool-result references. A
329
+ failed invocation writes paired JSON artifacts under:
330
+
331
+ ```text
332
+ ~/.pi/agent/openai-codex-compat-apply-patch-diagnostics/<session-id>/
333
+ ```
334
+
335
+ The active Pi agent directory replaces `~/.pi/agent` when configured
336
+ differently. The request artifact contains the raw patch, parsed instructions
337
+ (or parse failure), pre-execution snapshots for paths referenced by every
338
+ instruction in the failed patch, and available session, assistant, response,
339
+ turn, transport-request, and tool-call identifiers. It also records the
340
+ compatibility-package, Pi, Node.js, operating-system, and architecture versions.
341
+ Process identity, working directory, and umask are included when available.
342
+ Each file and parent-directory snapshot includes mode, size, modification time,
343
+ device, inode, link count, user ID, and group ID so hard-link, alias,
344
+ cross-filesystem, and permission failures remain traceable. Parent metadata is
345
+ collected from each referenced path through the filesystem root. Malformed
346
+ patches retain snapshots for every instruction recognized by the fallback
347
+ scanner.
348
+
349
+ Valid UTF-8 regular-file content is stored as text with its byte length and
350
+ SHA-256. Binary content is not copied; its snapshot contains only the byte
351
+ length and SHA-256. Symlink snapshots retain the raw target and either readable
352
+ UTF-8 target content or binary target metadata. The result artifact records the
353
+ failed outcome, structured tool details, and the error chain up to eight causes,
354
+ including available filesystem codes, operation names, source paths, and
355
+ destination paths. Those details also retain the diagnostic record ID and both
356
+ artifact paths so the invocation can be located from Pi session history.
357
+
358
+ These artifacts can contain sensitive source code, ownership and filesystem
359
+ identity metadata, absolute paths, patches, and request identifiers. Capture is
360
+ disabled by default.
361
+ Directories are restricted to mode `0700`, files to `0600`, and records are not
362
+ automatically pruned; delete them manually when they are no longer needed. If
363
+ either artifact cannot be written after a patch failure, the diagnostic error
364
+ is reported to stderr without replacing or changing the original patch
365
+ failure.
312
366
 
313
367
  Filesystem behavior:
314
368
 
315
369
  - Relative paths resolve from Pi's current working directory; absolute paths and `..` traversal are honored.
316
370
  - `.git` paths are unrestricted.
317
371
  - Text updates follow live symlinks; adds replace live or dangling symlinks without writing through them; deletes remove only the symlink; pure moves move the source symlink; and state-changing moves create a regular file at the destination without writing updated text through a source or destination symlink.
372
+ - Relative symlink targets, including targets containing `..`, resolve from
373
+ the canonical directory containing the link even when the source or moved
374
+ destination is reached through a symlink-parent alias.
318
375
  - Entry-only operations and no-op updates do not dereference cyclic or inaccessible symlink targets during mutation-queue acquisition.
319
376
  - Same-filesystem pure moves use native rename topology. Cross-filesystem moves copy through a temporary entry, create or replace the destination, and then unlink the source, producing an inode independent from remaining source hard links.
320
- - Strict and formatter-recovered edits preserve the matched region's local CRLF or mixed line endings.
377
+ - Supplied identity or context chunks validate a pure move through the text matcher without rewriting the moved entry. A blank `@@` therefore requires valid UTF-8; omit chunks for arbitrary binary content.
378
+ - Strict edits preserve the matched region's local CRLF or mixed line endings.
379
+ - In-place text updates use a direct path write, following source symlinks and
380
+ preserving normal hard-link visibility.
381
+ - Adds and text updates verify the complete expected final byte buffer
382
+ byte-for-byte before succeeding. This is whole-file equality, not a
383
+ substring search, so duplicate or unrelated regions cannot satisfy the
384
+ postcondition. Deletes verify absence; moves verify their source,
385
+ destination type, exact destination spelling, native identity where
386
+ available, known bytes, and raw symlink target.
321
387
  - The extension does not add path filtering, sandboxing, or approval prompts.
322
388
  - Every hunk is parsed and validated before filesystem writes begin.
323
- - Mutations participate in Pi's per-file mutation queue and an extension-local logical queue for case, Unicode, symlink-parent, and hard-link aliases. Both queues coordinate only concurrent `apply_patch` calls in the same Pi process and module instance; they do not coordinate separate Pi sessions, other processes, or unrelated edit/write tools.
389
+ - No-change checkpoints are interleaved with mutations in patch order, so
390
+ later checkpoints are not reported as completed after an earlier failure.
391
+ - Mutations participate in Pi's per-file mutation queue for the complete
392
+ preflight-and-execution window. Queue paths are acquired deterministically,
393
+ follow operation-specific symlink semantics, and include every move source
394
+ and destination. There is no additional extension-local alias queue.
395
+
396
+ Operating model: relevant filesystem state is not modified outside the queued
397
+ `apply_patch` execution window. This includes ancestor paths, symlink targets,
398
+ hard-link aliases, callbacks, injected filesystem hooks, separate Pi sessions,
399
+ and external processes. Preflight is authoritative under this model; the
400
+ executor does not attempt cross-process drift detection or transactional
401
+ isolation.
324
402
 
325
403
  A low-level I/O failure can still complete part of an instruction. The failed
326
404
  instruction reports every confirmed effect and final path state; when a path
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## OpenAI Codex
4
4
 
5
- The `apply_patch` grammar, parser behavior, fuzzy matching, mutation semantics, result formatting, diff rendering, standalone image-generation behavior, standalone web-search behavior, tool schemas, and compatibility scenarios in this package are adapted for Pi from the public OpenAI Codex implementation.
5
+ The `apply_patch` grammar, parser behavior, line matching, mutation semantics, result formatting, diff rendering, standalone image-generation behavior, standalone web-search behavior, tool schemas, and compatibility scenarios in this package are adapted for Pi from the public OpenAI Codex implementation.
6
6
 
7
7
  OpenAI Codex, Copyright 2025 OpenAI
8
8
 
@@ -19,29 +19,3 @@ Pi AI, Copyright (c) 2025 Mario Zechner
19
19
  Pi AI is licensed under the MIT License. A copy is included at [`LICENSES/pi-ai-MIT.txt`](LICENSES/pi-ai-MIT.txt).
20
20
 
21
21
  Source: <https://github.com/earendil-works/pi/tree/main/packages/ai>
22
-
23
- ## Tree-sitter WASMs
24
-
25
- `@2h2d/tree-sitter-wasms` supplies lifecycle-free grammar WASM assets used for
26
- formatter-tolerant `apply_patch` matching.
27
-
28
- Tree-sitter WASMs, Copyright (c) 2026 Kaan Ozdokmeci
29
-
30
- Tree-sitter WASMs is licensed under the MIT License. A copy is included at
31
- [`LICENSES/tree-sitter-wasms-MIT.txt`](LICENSES/tree-sitter-wasms-MIT.txt).
32
- The dependency package includes the exact upstream license for each bundled
33
- grammar under its own `LICENSES` directory.
34
-
35
- Source: <https://github.com/2h2d-co/tree-sitter-wasms>
36
-
37
- ## Web Tree-sitter
38
-
39
- `web-tree-sitter` supplies the official Tree-sitter WASM runtime used to load
40
- and execute the packaged grammars.
41
-
42
- Web Tree-sitter, Copyright (c) 2018 Max Brunsfeld
43
-
44
- Web Tree-sitter is licensed under the MIT License. A copy is included at
45
- [`LICENSES/web-tree-sitter-MIT.txt`](LICENSES/web-tree-sitter-MIT.txt).
46
-
47
- Source: <https://github.com/tree-sitter/tree-sitter/tree/master/lib/binding_web>