@volter/twin-openai 0.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +33 -30
  2. package/defaults/handlers.json +10 -0
  3. package/dist/defaults/handlers.json +10 -0
  4. package/dist/src/cli.d.ts +2 -0
  5. package/dist/src/cli.js +29 -0
  6. package/dist/src/generated/surface.gen.json +1 -0
  7. package/dist/src/generated/ui.gen.json +1 -0
  8. package/dist/src/index.d.ts +19 -0
  9. package/dist/src/index.js +72 -0
  10. package/dist/src/manifest.d.ts +6 -0
  11. package/dist/src/manifest.js +323 -0
  12. package/dist/src/openai-budget.d.ts +53 -0
  13. package/dist/src/openai-budget.js +147 -0
  14. package/dist/src/openai-capabilities.d.ts +4 -0
  15. package/dist/src/openai-capabilities.js +1569 -0
  16. package/dist/src/openai-conformance.d.ts +13 -0
  17. package/dist/src/openai-conformance.js +116 -0
  18. package/dist/src/openai-connector.d.ts +86 -0
  19. package/dist/src/openai-connector.js +291 -0
  20. package/dist/src/openai-media.d.ts +43 -0
  21. package/dist/src/openai-media.js +257 -0
  22. package/dist/src/openai-models.d.ts +74 -0
  23. package/dist/src/openai-models.js +148 -0
  24. package/dist/src/openai-scenario.d.ts +51 -0
  25. package/dist/src/openai-scenario.js +166 -0
  26. package/dist/src/openai-server.d.ts +40 -0
  27. package/dist/src/openai-server.js +126 -0
  28. package/dist/src/openai-stub.d.ts +82 -0
  29. package/dist/src/openai-stub.js +256 -0
  30. package/dist/src/openai-twin.d.ts +182 -0
  31. package/dist/src/openai-twin.js +1117 -0
  32. package/dist/src/openai-types.d.ts +194 -0
  33. package/dist/src/openai-types.js +4 -0
  34. package/dist/src/openai-webhooks.d.ts +47 -0
  35. package/dist/src/openai-webhooks.js +99 -0
  36. package/dist/src/screens/api-keys.d.ts +16 -0
  37. package/dist/src/screens/api-keys.js +131 -0
  38. package/dist/src/screens/session.d.ts +22 -0
  39. package/dist/src/screens/session.js +115 -0
  40. package/dist/src/semantics/assistants.d.ts +2 -0
  41. package/dist/src/semantics/assistants.js +331 -0
  42. package/dist/src/semantics/audio.d.ts +2 -0
  43. package/dist/src/semantics/audio.js +27 -0
  44. package/dist/src/semantics/batches.d.ts +4 -0
  45. package/dist/src/semantics/batches.js +86 -0
  46. package/dist/src/semantics/chat-completions.d.ts +3 -0
  47. package/dist/src/semantics/chat-completions.js +58 -0
  48. package/dist/src/semantics/containers.d.ts +2 -0
  49. package/dist/src/semantics/containers.js +147 -0
  50. package/dist/src/semantics/embeddings.d.ts +2 -0
  51. package/dist/src/semantics/embeddings.js +13 -0
  52. package/dist/src/semantics/evals.d.ts +2 -0
  53. package/dist/src/semantics/evals.js +173 -0
  54. package/dist/src/semantics/files.d.ts +13 -0
  55. package/dist/src/semantics/files.js +59 -0
  56. package/dist/src/semantics/fine-tuning.d.ts +4 -0
  57. package/dist/src/semantics/fine-tuning.js +178 -0
  58. package/dist/src/semantics/images.d.ts +2 -0
  59. package/dist/src/semantics/images.js +18 -0
  60. package/dist/src/semantics/index.d.ts +8 -0
  61. package/dist/src/semantics/index.js +46 -0
  62. package/dist/src/semantics/models.d.ts +2 -0
  63. package/dist/src/semantics/models.js +34 -0
  64. package/dist/src/semantics/moderations.d.ts +2 -0
  65. package/dist/src/semantics/moderations.js +12 -0
  66. package/dist/src/semantics/organization.d.ts +2 -0
  67. package/dist/src/semantics/organization.js +67 -0
  68. package/dist/src/semantics/progress.d.ts +22 -0
  69. package/dist/src/semantics/progress.js +63 -0
  70. package/dist/src/semantics/responses.d.ts +3 -0
  71. package/dist/src/semantics/responses.js +153 -0
  72. package/dist/src/semantics/shared.d.ts +32 -0
  73. package/dist/src/semantics/shared.js +69 -0
  74. package/dist/src/semantics/uploads.d.ts +2 -0
  75. package/dist/src/semantics/uploads.js +84 -0
  76. package/dist/src/semantics/vector-stores.d.ts +2 -0
  77. package/dist/src/semantics/vector-stores.js +281 -0
  78. package/dist/test-fixtures/openai-openapi-operations.SOURCE.md +18 -0
  79. package/dist/test-fixtures/openai-openapi-operations.json +1849 -0
  80. package/package.json +21 -10
  81. package/src/cli.ts +9 -7
  82. package/src/generated/surface.gen.json +1 -0
  83. package/src/generated/ui.gen.json +1 -0
  84. package/src/index.ts +20 -10
  85. package/src/manifest.ts +343 -0
  86. package/src/openai-budget.ts +4 -4
  87. package/src/openai-capabilities.ts +177 -195
  88. package/src/openai-conformance.ts +1 -1
  89. package/src/openai-connector.ts +40 -43
  90. package/src/openai-media.ts +225 -0
  91. package/src/openai-models.ts +145 -15
  92. package/src/openai-scenario.ts +46 -10
  93. package/src/openai-server.ts +65 -108
  94. package/src/openai-stub.ts +54 -30
  95. package/src/openai-twin.ts +760 -1665
  96. package/src/openai-types.ts +24 -6
  97. package/src/openai-webhooks.ts +2 -1
  98. package/src/screens/api-keys.tsx +138 -0
  99. package/src/screens/session.tsx +131 -0
  100. package/src/semantics/assistants.ts +336 -0
  101. package/src/semantics/audio.ts +31 -0
  102. package/src/semantics/batches.ts +88 -0
  103. package/src/semantics/chat-completions.ts +66 -0
  104. package/src/semantics/containers.ts +151 -0
  105. package/src/semantics/embeddings.ts +19 -0
  106. package/src/semantics/evals.ts +182 -0
  107. package/src/semantics/files.ts +67 -0
  108. package/src/semantics/fine-tuning.ts +185 -0
  109. package/src/semantics/images.ts +23 -0
  110. package/src/semantics/index.ts +52 -0
  111. package/src/semantics/models.ts +41 -0
  112. package/src/semantics/moderations.ts +14 -0
  113. package/src/semantics/organization.ts +76 -0
  114. package/src/semantics/progress.ts +72 -0
  115. package/src/semantics/responses.ts +151 -0
  116. package/src/semantics/shared.ts +82 -0
  117. package/src/semantics/uploads.ts +92 -0
  118. package/src/semantics/vector-stores.ts +279 -0
  119. package/test-fixtures/openai-openapi-operations.SOURCE.md +4 -5
  120. package/test-fixtures/openai-openapi-operations.json +224 -1334
@@ -0,0 +1 @@
1
+ {"generatedBy":"scripts/derive-pack.ts","resources":{"Model":{"list":"/v1/models","retrieve":"/v1/models/{model}","actions":[],"states":{},"embeds":{}},"OpenAIFile":{"list":"/v1/files","retrieve":"/v1/files/{file_id}","create":{"path":"/v1/files","encoding":"multipart","body":[{"name":"expires_after","type":"FileExpirationAfter","required":false},{"name":"file","type":"string","required":true},{"name":"purpose","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"FineTuningJob":{"list":"/v1/fine_tuning/jobs","retrieve":"/v1/fine_tuning/jobs/{fine_tuning_job_id}","create":{"path":"/v1/fine_tuning/jobs","encoding":"json","body":[{"name":"hyperparameters","type":"object","required":false},{"name":"integrations","type":"array","required":false},{"name":"metadata","type":"Metadata","required":false},{"name":"method","type":"FineTuneMethod","required":false},{"name":"model","type":"union","required":true},{"name":"seed","type":"integer","required":false},{"name":"suffix","type":"string","required":false},{"name":"training_file","type":"string","required":true},{"name":"validation_file","type":"string","required":false}]},"actions":[{"operation":"cancelFineTuningJob","method":"POST","path":"/v1/fine_tuning/jobs/{fine_tuning_job_id}/cancel","field":"status","from":["validating_files","queued","running","paused"],"to":"cancelled"},{"operation":"pauseFineTuningJob","method":"POST","path":"/v1/fine_tuning/jobs/{fine_tuning_job_id}/pause","field":"status","from":["validating_files","queued","running"],"to":"paused"},{"operation":"resumeFineTuningJob","method":"POST","path":"/v1/fine_tuning/jobs/{fine_tuning_job_id}/resume","field":"status","from":["paused"],"to":"queued"}],"states":{"status":["cancelled","paused","queued","running","succeeded","validating_files"]},"embeds":{}},"FineTuningJobEvent":{"list":"/v1/fine_tuning/jobs/{fine_tuning_job_id}/events","actions":[],"states":{},"embeds":{}},"FineTuningJobCheckpoint":{"list":"/v1/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints","actions":[],"states":{},"embeds":{}},"VectorStoreObject":{"list":"/v1/vector_stores","retrieve":"/v1/vector_stores/{vector_store_id}","create":{"path":"/v1/vector_stores","encoding":"json","body":[{"name":"chunking_strategy","type":"union","required":false},{"name":"description","type":"string","required":false},{"name":"expires_after","type":"VectorStoreExpirationAfter","required":false},{"name":"file_ids","type":"array","required":false},{"name":"metadata","type":"Metadata","required":false},{"name":"name","type":"string","required":false}]},"actions":[],"states":{"status":["completed"]},"embeds":{}},"VectorStoreFileObject":{"list":"/v1/vector_stores/{vector_store_id}/files","retrieve":"/v1/vector_stores/{vector_store_id}/files/{file_id}","create":{"path":"/v1/vector_stores/{vector_store_id}/files","encoding":"json","body":[{"name":"attributes","type":"VectorStoreFileAttributes","required":false},{"name":"chunking_strategy","type":"ChunkingStrategyRequestParam","required":false},{"name":"file_id","type":"string","required":true}]},"actions":[],"states":{"status":["cancelled","completed","in_progress"]},"embeds":{}},"VectorStoreFileBatchObject":{"retrieve":"/v1/vector_stores/{vector_store_id}/file_batches/{batch_id}","create":{"path":"/v1/vector_stores/{vector_store_id}/file_batches","encoding":"json","body":[{"name":"attributes","type":"VectorStoreFileAttributes","required":false},{"name":"chunking_strategy","type":"ChunkingStrategyRequestParam","required":false},{"name":"file_ids","type":"array","required":false},{"name":"files","type":"array","required":false}]},"actions":[{"operation":"cancelVectorStoreFileBatch","method":"POST","path":"/v1/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel","field":"status","from":["in_progress"],"to":"cancelled"}],"states":{"status":["cancelled","completed","in_progress"]},"embeds":{}},"CreateChatCompletionResponse":{"list":"/v1/chat/completions","retrieve":"/v1/chat/completions/{completion_id}","create":{"path":"/v1/chat/completions","encoding":"json","body":[]},"actions":[],"states":{},"embeds":{}},"Response":{"retrieve":"/v1/responses/{response_id}","create":{"path":"/v1/responses","encoding":"json","body":[]},"actions":[{"operation":"cancelResponse","method":"POST","path":"/v1/responses/{response_id}/cancel","field":"status","from":["queued","in_progress"],"to":"cancelled"},{"operation":"cancelResponse","method":"POST","path":"/v1/responses/{response_id}/cancel","field":"status","from":["cancelled"]}],"states":{"status":["cancelled","completed","in_progress","queued"]},"embeds":{}},"BetaResponse":{"retrieve":"/v1/responses/{response_id}","create":{"path":"/v1/responses","encoding":"json","body":[]},"actions":[{"operation":"beta_cancelResponse","method":"POST","path":"/v1/responses/{response_id}/cancel","field":"status","from":["queued","in_progress"],"to":"cancelled"},{"operation":"beta_cancelResponse","method":"POST","path":"/v1/responses/{response_id}/cancel","field":"status","from":["cancelled"]}],"states":{"status":["cancelled","completed","in_progress","queued"]},"embeds":{}},"ItemResource":{"list":"/v1/responses/{response_id}/input_items","actions":[],"states":{},"embeds":{}},"BetaItemResource":{"list":"/v1/responses/{response_id}/input_items","actions":[],"states":{},"embeds":{}},"AssistantObject":{"list":"/v1/assistants","retrieve":"/v1/assistants/{assistant_id}","create":{"path":"/v1/assistants","encoding":"json","body":[{"name":"description","type":"union","required":false},{"name":"instructions","type":"union","required":false},{"name":"metadata","type":"Metadata","required":false},{"name":"model","type":"union","required":true},{"name":"name","type":"union","required":false},{"name":"reasoning_effort","type":"ReasoningEffort","required":false},{"name":"response_format","type":"union","required":false},{"name":"temperature","type":"union","required":false},{"name":"tool_resources","type":"union","required":false},{"name":"tools","type":"array","required":false},{"name":"top_p","type":"union","required":false}]},"actions":[],"states":{},"embeds":{}},"ThreadObject":{"retrieve":"/v1/threads/{thread_id}","create":{"path":"/v1/threads","encoding":"json","body":[{"name":"messages","type":"array","required":false},{"name":"metadata","type":"Metadata","required":false},{"name":"tool_resources","type":"union","required":false}]},"actions":[],"states":{},"embeds":{}},"MessageObject":{"list":"/v1/threads/{thread_id}/messages","retrieve":"/v1/threads/{thread_id}/messages/{message_id}","create":{"path":"/v1/threads/{thread_id}/messages","encoding":"json","body":[{"name":"attachments","type":"union","required":false},{"name":"content","type":"union","required":true},{"name":"metadata","type":"Metadata","required":false},{"name":"role","type":"string","required":true}]},"actions":[],"states":{},"embeds":{}},"RunObject":{"list":"/v1/threads/{thread_id}/runs","retrieve":"/v1/threads/{thread_id}/runs/{run_id}","create":{"path":"/v1/threads/{thread_id}/runs","encoding":"json","body":[{"name":"additional_instructions","type":"string","required":false},{"name":"additional_messages","type":"array","required":false},{"name":"assistant_id","type":"string","required":true},{"name":"instructions","type":"string","required":false},{"name":"max_completion_tokens","type":"integer","required":false},{"name":"max_prompt_tokens","type":"integer","required":false},{"name":"metadata","type":"Metadata","required":false},{"name":"model","type":"union","required":false},{"name":"parallel_tool_calls","type":"ParallelToolCalls","required":false},{"name":"reasoning_effort","type":"ReasoningEffort","required":false},{"name":"response_format","type":"AssistantsApiResponseFormatOption","required":false},{"name":"stream","type":"boolean","required":false},{"name":"temperature","type":"number","required":false},{"name":"tool_choice","type":"any","required":false},{"name":"tools","type":"array","required":false},{"name":"top_p","type":"number","required":false},{"name":"truncation_strategy","type":"any","required":false}]},"actions":[{"operation":"cancelRun","method":"POST","path":"/v1/threads/{thread_id}/runs/{run_id}/cancel","field":"status","from":["queued","in_progress","requires_action"],"to":"cancelling"},{"operation":"submitToolOuputsToRun","method":"POST","path":"/v1/threads/{thread_id}/runs/{run_id}/submit_tool_outputs","field":"status","from":["requires_action"],"to":"queued"}],"states":{"status":["cancelled","cancelling","completed","in_progress","queued","requires_action"]},"embeds":{}},"RunStepObject":{"list":"/v1/threads/{thread_id}/runs/{run_id}/steps","retrieve":"/v1/threads/{thread_id}/runs/{run_id}/steps/{step_id}","actions":[],"states":{},"embeds":{}},"Project":{"list":"/v1/organization/projects","retrieve":"/v1/organization/projects/{project_id}","create":{"path":"/v1/organization/projects","encoding":"json","body":[{"name":"external_key_id","type":"union","required":false},{"name":"geography","type":"union","required":false},{"name":"name","type":"string","required":true},{"name":"residency","type":"union","required":false}]},"actions":[{"operation":"archive-project","method":"POST","path":"/v1/organization/projects/{project_id}/archive","field":"status","from":"*","to":"archived"}],"states":{"status":["active","archived"]},"embeds":{}},"ProjectApiKey":{"list":"/v1/organization/projects/{project_id}/api_keys","retrieve":"/v1/organization/projects/{project_id}/api_keys/{api_key_id}","actions":[],"states":{},"embeds":{}},"UsageTimeBucket":{"list":"/v1/organization/costs","actions":[],"states":{},"embeds":{}},"Eval":{"list":"/v1/evals","retrieve":"/v1/evals/{eval_id}","create":{"path":"/v1/evals","encoding":"json","body":[{"name":"data_source_config","type":"union","required":true},{"name":"metadata","type":"Metadata","required":false},{"name":"name","type":"string","required":false},{"name":"testing_criteria","type":"array","required":true}]},"actions":[],"states":{},"embeds":{}},"EvalRun":{"list":"/v1/evals/{eval_id}/runs","retrieve":"/v1/evals/{eval_id}/runs/{run_id}","create":{"path":"/v1/evals/{eval_id}/runs","encoding":"json","body":[{"name":"data_source","type":"union","required":true},{"name":"metadata","type":"Metadata","required":false},{"name":"name","type":"string","required":false}]},"actions":[{"operation":"cancelEvalRun","method":"POST","path":"/v1/evals/{eval_id}/runs/{run_id}","field":"status","from":["queued","in_progress"],"to":"canceled"}],"states":{"status":["canceled","completed","in_progress","queued"]},"embeds":{}},"EvalRunOutputItem":{"list":"/v1/evals/{eval_id}/runs/{run_id}/output_items","actions":[],"states":{},"embeds":{}},"ContainerResource":{"list":"/v1/containers","retrieve":"/v1/containers/{container_id}","create":{"path":"/v1/containers","encoding":"json","body":[{"name":"expires_after","type":"object","required":false},{"name":"file_ids","type":"array","required":false},{"name":"memory_limit","type":"string","required":false},{"name":"name","type":"string","required":true},{"name":"network_policy","type":"union","required":false},{"name":"skills","type":"array","required":false}]},"actions":[],"states":{"status":["expired","running"]},"embeds":{}},"ContainerFileResource":{"list":"/v1/containers/{container_id}/files","retrieve":"/v1/containers/{container_id}/files/{file_id}","create":{"path":"/v1/containers/{container_id}/files","encoding":"json","body":[{"name":"file","type":"string","required":false},{"name":"file_id","type":"string","required":false}]},"actions":[],"states":{},"embeds":{}},"Batch":{"list":"/v1/batches","retrieve":"/v1/batches/{batch_id}","create":{"path":"/v1/batches","encoding":"json","body":[{"name":"completion_window","type":"string","required":true},{"name":"endpoint","type":"string","required":true},{"name":"input_file_id","type":"string","required":true},{"name":"metadata","type":"Metadata","required":false},{"name":"output_expires_after","type":"BatchFileExpirationAfter","required":false}]},"actions":[{"operation":"cancelBatch","method":"POST","path":"/v1/batches/{batch_id}/cancel","field":"status","from":["validating","in_progress","finalizing"],"to":"cancelling"}],"states":{"status":["cancelled","cancelling","completed","finalizing","in_progress","validating"]},"embeds":{}},"Upload":{"actions":[],"states":{"status":["cancelled","completed","expired","pending"]},"embeds":{}}}}
@@ -0,0 +1,19 @@
1
+ export { handleOpenAITwinRequest, streamChat } from './openai-twin.js';
2
+ export type { OpenAIRequest, OpenAIResponseEnvelope } from './openai-twin.js';
3
+ export { createOpenAITwinFetch, createOpenAITwinServer } from './openai-server.js';
4
+ export type { OpenAITwinFetchOptions } from './openai-server.js';
5
+ export { OPENAI_MODELS, findModel } from './openai-models.js';
6
+ export type { OpenAIModel } from './openai-models.js';
7
+ export { countPromptTokens, estimateTokens, stubAssistantText, stubToolCall, contentToText, lastUserText, pseudoEmbedding, moderateText, MODERATION_CATEGORIES, } from './openai-stub.js';
8
+ export type { ModerationResult } from './openai-stub.js';
9
+ export type { ChatMessageParam, ChatToolCall, ChatCompletion, ChatChoice, ChatUsage, OpenAIResponse, EmbeddingResponse, Embedding, OpenAIError, SseEvent, SseSink, } from './openai-types.js';
10
+ export { performOpenAIAction, openaiExecuteOver, openaiRequestForAction, liveOpenAIExecute, mapFile, mapBatch, mapFineTune, mapVectorStore, pullOpenAIState, pushOpenAIAction, syncOpenAIFromReal, } from './openai-connector.js';
11
+ export type { OpenAIExecute, LiveOpenAIOptions } from './openai-connector.js';
12
+ export { OPENAI_BUDGET_CEILING, OPENAI_BUDGET_MAX_RETRY_AFTER_S, OPENAI_BUDGET_WINDOW_MS, OPENAI_CALL_WEIGHTS, OPENAI_RATE_BUDGET, OpenAIBudget, OpenAIBudgetError, openaiBudgetPath, openaiCallWeight, } from './openai-budget.js';
13
+ export type { OpenAIBudgetErrorKind, OpenAIBudgetOptions, OpenAIBudgetReservation, OpenAIBudgetSnapshot } from './openai-budget.js';
14
+ export { verifyOpenAIWebhook, computeOpenAIWebhookSignature, buildSignedOpenAIWebhook, OpenAIWebhookVerificationError, OPENAI_WEBHOOK_EVENT_TYPES, } from './openai-webhooks.js';
15
+ export type { OpenAIWebhookEvent } from './openai-webhooks.js';
16
+ import type { TwinPack } from '@volter/world-core';
17
+ export declare const pack: TwinPack;
18
+ export { createOpenAIScenarioEngine, loadOpenAIScenarioDocument, openaiScenarioAdapter, realizeOpenAIRespond } from './openai-scenario.js';
19
+ export type { OpenAIScenarioEngine, OpenAIScenarioRequest, OpenAIScenarioRespond } from './openai-scenario.js';
@@ -0,0 +1,72 @@
1
+ // @volter/twin-openai — the OpenAI twin (one vendor, one package), built on the shared
2
+ // @volter/world-core kernel. The OpenAI API: a vendor-faithful protocol envelope (chat
3
+ // completions/streaming/tool_calls, the Responses API, embeddings), a static models catalog,
4
+ // deterministic moderations, and STATEFUL files / batches / fine-tuning jobs / vector stores —
5
+ // over an event/action log. (OpenAI is an API-first vendor with no meaningful product UI worth
6
+ // mirroring — docs/contributing/architecture.md C1b — so this pack ships no mirror.)
7
+ //
8
+ // THE HONEST CARVE-OUTS: the twin cannot run the model, so POST /v1/chat/completions and
9
+ // /v1/responses return a DETERMINISTIC STUB completion (clearly labeled), and /v1/embeddings
10
+ // returns DETERMINISTIC pseudo-vectors — never pretending to be real inference. Everything
11
+ // around them — the wire protocol — is faithful. (Conformance + capability tooling live in
12
+ // @volter/world-tooling, a dev dependency — NOT re-exported here, per E2.)
13
+ export { handleOpenAITwinRequest, streamChat } from "./openai-twin.js";
14
+ export { createOpenAITwinFetch, createOpenAITwinServer } from "./openai-server.js";
15
+ export { OPENAI_MODELS, findModel } from "./openai-models.js";
16
+ export { countPromptTokens, estimateTokens, stubAssistantText, stubToolCall, contentToText, lastUserText, pseudoEmbedding, moderateText, MODERATION_CATEGORIES, } from "./openai-stub.js";
17
+ export { performOpenAIAction, openaiExecuteOver, openaiRequestForAction, liveOpenAIExecute, mapFile, mapBatch, mapFineTune, mapVectorStore, pullOpenAIState, pushOpenAIAction, syncOpenAIFromReal, } from "./openai-connector.js";
18
+ // The client-side rate budget — the fail-closed backstop `liveOpenAIExecute` routes every live
19
+ // request through. The MECHANISM is the kernel's shared, vendor-agnostic `RateBudget`; what lives
20
+ // here is OpenAI's DECLARATION (window/ceiling/per-endpoint weights) plus the vendor-bound
21
+ // bindings. Exported so an operator can inspect spend (`snapshot`) and so a caller can catch
22
+ // `OpenAIBudgetError` by type; there is deliberately no export that disables the guard.
23
+ export { OPENAI_BUDGET_CEILING, OPENAI_BUDGET_MAX_RETRY_AFTER_S, OPENAI_BUDGET_WINDOW_MS, OPENAI_CALL_WEIGHTS, OPENAI_RATE_BUDGET, OpenAIBudget, OpenAIBudgetError, openaiBudgetPath, openaiCallWeight, } from "./openai-budget.js";
24
+ export { verifyOpenAIWebhook, computeOpenAIWebhookSignature, buildSignedOpenAIWebhook, OpenAIWebhookVerificationError, OPENAI_WEBHOOK_EVENT_TYPES, } from "./openai-webhooks.js";
25
+ import { registerPack } from '@volter/world-core';
26
+ import { OPENAI_RATE_BUDGET as RATE_BUDGET } from "./openai-budget.js";
27
+ import { performOpenAIAction } from "./openai-connector.js";
28
+ export const pack = {
29
+ vendor: 'openai',
30
+ // PROTOCOL 2 (docs/contributing/architecture.md#protocol-2-the-pack-is-a-plugin): the wire, the tree, and the real apply — a recorded call
31
+ // forwarded as the same request. A generative vendor has no state to refresh from.
32
+ protocol: '2',
33
+ stateSystem: { perform: performOpenAIAction },
34
+ roundTrip: { method: 'POST', path: '/v1/chat/completions', body: { model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'round trip' }] }, headers: { authorization: 'Bearer sk-round-trip' } },
35
+ // The SAME object openai-budget.ts declares at module load — one source of truth, so registering
36
+ // the pack and importing the connector can never arm two different ceilings.
37
+ rateBudget: RATE_BUDGET,
38
+ transport: 'rest',
39
+ archetype: 'generative',
40
+ bin: 'world-openai',
41
+ resources: ['file', 'batch', 'fine_tuning_job', 'vector_store', 'vector_store_file', 'response', 'chat_completion'],
42
+ specSource: 'OpenAI API (envelope-faithful; model output is a deterministic stub, embeddings are deterministic pseudo-vectors)',
43
+ description: 'OpenAI API twin — faithful protocol envelope (chat completions/streaming/tool_calls, Responses API, embeddings), models, moderations, stateful files/batches/fine-tuning/vector stores; generative output is a labeled stub.',
44
+ // Adoption + interception, all in the pack's one home (descriptor-first back-migration, adding-a-twin.md §3,
45
+ // 2026-08-31; the bare `openai` stem and both SDK names moved off the central maps unchanged).
46
+ // The stems are the bare OPENAI_* pair plus the credential-var shapes real apps use beside it
47
+ // (AP_OPENAI_*, OPENAI_MODERATION_*).
48
+ adoption: {
49
+ // OpenAI's official Python library and Agents SDK. THE DISTRIBUTION IS THE CLAIM: `openai` stays
50
+ // this pack's even when a caller points it at DeepSeek, xAI, OpenRouter, Perplexity, an AI Gateway
51
+ // or an Azure OpenAI endpoint - those packs claim the ENDPOINT ENV that routes it, never this name.
52
+ // `tiktoken` is deliberately UNCLAIMED: it is a local tokenizer that makes no API call at all.
53
+ pypi: ['openai', 'openai-agents'],
54
+ sdks: ['openai', '@ai-sdk/openai'],
55
+ // 'REWORKDPLATFORMOPENAI' — AgentGPT names its key REWORKD_PLATFORM_OPENAI_API_KEY, the same
56
+ // app-prefixed shape as APOPENAI (ladder classification 2026-09-02). Deliberately NOT
57
+ // 'OPENAIOAUTH': postiz's OPENAI_OAUTH_CLIENT_ID is the client id its own MCP OAuth SERVER
58
+ // accepts from the ChatGPT connector — inbound, no api.openai.com call — so it is ruled
59
+ // not-a-vendor in the packless registry instead.
60
+ envStems: ['OPENAI', 'APOPENAI', 'OPENAIMODERATION', 'REWORKDPLATFORMOPENAI'],
61
+ },
62
+ // The whole REST surface the `openai` SDK talks to uses one base, https://api.openai.com — the
63
+ // same default the pack's own connector pins (openai-connector.ts).
64
+ hosts: [{ host: 'api.openai.com' }, { host: 'platform.openai.com', pathPattern: '^/(settings/proj[-_][^/]+/api-keys|login$)' }],
65
+ // The SDK calls the same-origin '/v1/…' and loads from api.openai.com — the dev proxy
66
+ // forwards '/v1/' to the twin and strips the absolute host so calls come back same-origin.
67
+ browserRouting: { apiPathPrefix: '/v1/', loaderHost: 'https://api.openai.com' },
68
+ };
69
+ export { createOpenAIScenarioEngine, loadOpenAIScenarioDocument, openaiScenarioAdapter, realizeOpenAIRespond } from "./openai-scenario.js";
70
+ // PROTOCOL 2: the pack registers itself on load — its rate budget and its state system (the head
71
+ // resolves `stateSystemFor(vendor)` in the process that serves the twin).
72
+ registerPack(pack);
@@ -0,0 +1,6 @@
1
+ import type { DerivedManifest } from '@volter/world-core';
2
+ /** A file attached to a store as OpenAI shows it: its id is the file's, not the twin's composite key. */
3
+ export declare function vectorStoreFileView(body: Record<string, unknown>, subject: {
4
+ id: string;
5
+ }): Record<string, unknown>;
6
+ export declare const manifest: DerivedManifest;
@@ -0,0 +1,323 @@
1
+ const vendor = (from, to, source, effects) => ({ actor: 'vendor', from, to, source, ...(effects ? { effects } : {}) });
2
+ const time = (from, to, source, effects) => ({ actor: 'time', from, to, source, ...(effects ? { effects } : {}) });
3
+ /** A Batch's `status`. OpenAI validates, runs and finalizes a batch on its own; the twin does that work
4
+ * when a read first looks (semantics/progress.ts). Only a batch still in flight can be cancelled: it is
5
+ * `cancelling` until OpenAI stops it (https://platform.openai.com/docs/guides/batch#batch-object). */
6
+ const BATCH_DOCS = 'spec:/components/schemas/Batch/properties/status "The current status of the batch."';
7
+ const batchStatus = {
8
+ initial: 'validating',
9
+ transitions: [
10
+ {
11
+ operation: 'cancelBatch',
12
+ from: ['validating', 'in_progress', 'finalizing'],
13
+ to: 'cancelling',
14
+ effects: { cancelling_at: { now: true } },
15
+ refusal: { status: 409, message: "Cannot cancel a batch with status '{from}'." },
16
+ source: 'spec:cancelBatch "The batch will be in status `cancelling` for up to 10 minutes, before changing to `cancelled`"',
17
+ },
18
+ vendor(['validating'], 'in_progress', BATCH_DOCS, { in_progress_at: { now: true } }),
19
+ vendor(['in_progress'], 'finalizing', BATCH_DOCS, { finalizing_at: { now: true } }),
20
+ vendor(['finalizing'], 'completed', BATCH_DOCS, { completed_at: { now: true } }),
21
+ vendor(['cancelling'], 'cancelled', BATCH_DOCS, { cancelled_at: { now: true } }),
22
+ // OpenAI also fails a batch whose input does not validate and expires one not done in its completion
23
+ // window; the twin validates every input and works a batch the moment a read looks, so it does neither
24
+ ],
25
+ };
26
+ /** A fine-tuning job's `status`. OpenAI validates the files, queues and trains on its own; the twin
27
+ * finishes that work when a read first looks, unless the job is paused. Cancel stops a job still in
28
+ * flight, pause one not yet finished, resume a paused one. `paused` is OpenAI's, though its spec's
29
+ * enum omits it. A resumed job is queued again. */
30
+ const invalidStatus = (verb) => ({ status: 400, code: 'invalid_status', message: `Cannot ${verb} a job with status '{from}'.` });
31
+ const FT_DOCS = 'spec:/components/schemas/FineTuningJob/properties/status "The current status of the fine-tuning job"';
32
+ const fineTuningJobStatus = {
33
+ initial: 'validating_files',
34
+ transitions: [
35
+ { operation: 'cancelFineTuningJob', from: ['validating_files', 'queued', 'running', 'paused'], to: 'cancelled', refusal: invalidStatus('cancel'), source: 'spec:cancelFineTuningJob "Immediately cancel a fine-tune job."' },
36
+ { operation: 'pauseFineTuningJob', from: ['validating_files', 'queued', 'running'], to: 'paused', refusal: invalidStatus('pause'), source: 'spec:pauseFineTuningJob "Pause a fine-tune job."' },
37
+ // a resumed job queues again (the reference's resume example answers `"status": "queued"`)
38
+ { operation: 'resumeFineTuningJob', from: ['paused'], to: 'queued', refusal: invalidStatus('resume'), source: 'spec:resumeFineTuningJob "Resume a fine-tune job."' },
39
+ vendor(['validating_files'], 'queued', FT_DOCS),
40
+ vendor(['queued'], 'running', FT_DOCS),
41
+ vendor(['running'], 'succeeded', FT_DOCS, { finished_at: { now: true } }),
42
+ // OpenAI also fails a job whose files do not validate; the twin trains on any file, so none fails
43
+ ],
44
+ };
45
+ /** A response's `status`, for the GA and the beta operations alike. A foreground response is answered
46
+ * `completed`; a background one is created `queued` and OpenAI works it on its own, over time on the
47
+ * World clock. Only a queued or in-progress one can be cancelled, and cancelling a
48
+ * cancelled one again answers it as it is (https://platform.openai.com/docs/guides/background). */
49
+ const BACKGROUND = 'https://platform.openai.com/docs/guides/background';
50
+ const responseStatus = (prefix) => ({
51
+ initial: 'completed',
52
+ transitions: [
53
+ {
54
+ operation: `${prefix}cancelResponse`,
55
+ from: ['queued', 'in_progress'],
56
+ to: 'cancelled',
57
+ refusal: { status: 400, code: 'invalid_status', message: "Cannot cancel a response with status '{from}'." },
58
+ source: 'spec:cancelResponse "Only responses created with the `background` parameter set to `true` can be cancelled."',
59
+ },
60
+ { operation: `${prefix}cancelResponse`, from: ['cancelled'], source: BACKGROUND },
61
+ // OpenAI writes a background response over time: queued, in progress, completed (semantics/responses.ts
62
+ // times it); it may also fail it or leave it incomplete, which a stub that runs no model never does
63
+ vendor(['queued'], 'in_progress', BACKGROUND),
64
+ vendor(['queued', 'in_progress'], 'completed', BACKGROUND),
65
+ ],
66
+ });
67
+ /** A run's `status`. OpenAI queues a run and works it on its own, stopping at `requires_action` for
68
+ * its function tools' outputs; the twin works it when a read first looks: a run with function tools
69
+ * stops for them (the placeholder model calls them), then, once they are submitted, ends with a labeled
70
+ * stub reply. Only a run in flight can be cancelled (`cancelling` until OpenAI stops it), and only one
71
+ * waiting on tools takes outputs. */
72
+ const RUN_DOCS = 'spec:/components/schemas/RunObject/properties/status "The status of the run, which can be either `queued`, `in_progress`, `requires_action`, `cancelling`, `cancelled`, `failed`, `completed`, `incomplete`"';
73
+ const runStatus = {
74
+ initial: 'queued',
75
+ transitions: [
76
+ {
77
+ operation: 'cancelRun',
78
+ from: ['queued', 'in_progress', 'requires_action'],
79
+ to: 'cancelling',
80
+ // a run being cancelled needs no action ("Will be `null` if no action is required", RunObject.required_action)
81
+ effects: { required_action: { value: null } },
82
+ refusal: { status: 400, message: "Cannot cancel run with status '{from}'." },
83
+ source: 'spec:cancelRun "Cancels a run that is `in_progress`."',
84
+ },
85
+ {
86
+ operation: 'submitToolOuputsToRun',
87
+ from: ['requires_action'],
88
+ to: 'queued',
89
+ refusal: { status: 400, message: 'Runs in status "{from}" do not accept tool outputs.' },
90
+ source: 'spec:submitToolOuputsToRun "When a run has the `status: \"requires_action\"`"',
91
+ },
92
+ vendor(['queued'], 'in_progress', RUN_DOCS, { started_at: { now: true } }),
93
+ vendor(['in_progress'], 'completed', RUN_DOCS, { completed_at: { now: true } }),
94
+ // a run whose model calls its function tools stops for their outputs
95
+ // (https://platform.openai.com/docs/assistants/tools/function-calling)
96
+ vendor(['in_progress'], 'requires_action', RUN_DOCS),
97
+ vendor(['cancelling'], 'cancelled', RUN_DOCS, { cancelled_at: { now: true } }),
98
+ // OpenAI also fails a run, leaves it incomplete or expires it; the twin's stub model never does
99
+ ],
100
+ };
101
+ /** A project's `status`: archive moves any project to `archived`, stamping when. */
102
+ const projectStatus = {
103
+ initial: 'active',
104
+ transitions: [
105
+ { operation: 'archive-project', from: '*', to: 'archived', effects: { archived_at: { now: true } }, source: 'spec:archive-project "Archives a project in the organization. Archived projects cannot be used or updated."' },
106
+ ],
107
+ };
108
+ /** A vector store's `status`: it is `in_progress` while OpenAI embeds files added to it, and expires
109
+ * when its `expires_after` policy runs out. The twin embeds nothing, so a store stays `completed`. */
110
+ // the twin neither embeds nor keeps an expiry policy, so no move of a store's status is the twin's
111
+ // (OpenAI's: "The status of the vector store, which can be either `expired`, `in_progress`, or `completed`.")
112
+ const vectorStoreStatus = { initial: 'completed', transitions: [] };
113
+ /** A file attached to a store, or a batch of them: OpenAI processes it on its own (the twin, when a read
114
+ * first looks); cancelling the batch cancels what is still in progress, and a finished batch is refused. */
115
+ // Extrapolation: the wording of OpenAI's refusal to cancel a finished batch or eval run is not sourced from
116
+ // a recording; that only one in progress can be cancelled is (the spec's operation descriptions).
117
+ const notInFlight = (what) => ({ status: 400, message: `Cannot cancel ${what} with status '{from}'.` });
118
+ const vectorStoreFileStatus = (source, refusal) => ({
119
+ initial: 'in_progress',
120
+ transitions: [
121
+ // the batch is the cancel's subject (its files stop when the cancel lands, the vendor's move below)
122
+ ...(refusal ? [{ operation: 'cancelVectorStoreFileBatch', from: ['in_progress'], to: 'cancelled', refusal, source: 'spec:cancelVectorStoreFileBatch "Cancel a vector store file batch."' }] : []),
123
+ vendor(['in_progress'], 'completed', source),
124
+ // a cancel asked for lands once the work in flight is done (semantics/vector-stores.ts)
125
+ vendor(['in_progress'], 'cancelled', 'spec:cancelVectorStoreFileBatch "This attempts to cancel the processing of files in this batch as soon as possible."'),
126
+ // OpenAI fails a file it cannot parse; the twin embeds nothing, so none fails
127
+ ],
128
+ });
129
+ /** An Upload's `status` (the spec declares no Upload resource: semantics/uploads.ts serves it). Parts
130
+ * are added and it is completed or cancelled only while `pending`; an hour after creation it expires.
131
+ * OpenAI answers a finished Upload as though it were not there. */
132
+ const UPLOAD_DOCS = 'spec:/components/schemas/Upload/properties/status "The status of the Upload."';
133
+ const noUpload = { status: 404, message: 'No such Upload object: {id}' };
134
+ const uploadStatus = {
135
+ initial: 'pending',
136
+ transitions: [
137
+ { operation: 'addUploadPart', from: ['pending'], refusal: noUpload, source: 'spec:addUploadPart "Adds a [Part]"' },
138
+ { operation: 'completeUpload', from: ['pending'], to: 'completed', refusal: noUpload, source: 'spec:completeUpload "Completes the [Upload]"' },
139
+ { operation: 'cancelUpload', from: ['pending'], to: 'cancelled', refusal: noUpload, source: 'spec:cancelUpload "No Parts may be added after an Upload is cancelled."' },
140
+ time(['pending'], 'expired', UPLOAD_DOCS),
141
+ ],
142
+ };
143
+ /** A container's `status`: running while in use, expired once idle past its `expires_after` (by default
144
+ * 20 minutes after `last_active_at`), observed when a read or a use looks (semantics/containers.ts).
145
+ * An expired container's files can no longer be listed, read, added or removed. */
146
+ const CONTAINERS = 'https://platform.openai.com/docs/guides/tools-code-interpreter#containers';
147
+ // Extrapolation: the status, code and wording of OpenAI's refusal to use an expired container are not
148
+ // sourced from a recording; the rule that an expired container cannot be used is (CONTAINERS).
149
+ const containerExpired = { status: 400, code: 'container_expired', message: 'Container {id} is expired.' };
150
+ const inRunning = (operation) => ({ operation, from: ['running'], refusal: containerExpired, source: CONTAINERS });
151
+ const containerStatus = {
152
+ initial: 'running',
153
+ transitions: [
154
+ time(['running'], 'expired', CONTAINERS),
155
+ ...['CreateContainerFile', 'ListContainerFiles', 'RetrieveContainerFile', 'RetrieveContainerFileContent', 'DeleteContainerFile'].map(inRunning),
156
+ ],
157
+ };
158
+ /** An eval run's `status`: OpenAI queues and grades it on its own; the twin grades it (a stub grader)
159
+ * when a read first looks. A run in flight can be cancelled. */
160
+ const EVAL_DOCS = 'spec:/components/schemas/EvalRun/properties/status "The status of the evaluation run."';
161
+ const evalRunStatus = {
162
+ initial: 'queued',
163
+ transitions: [
164
+ { operation: 'cancelEvalRun', from: ['queued', 'in_progress'], to: 'canceled', refusal: notInFlight('an eval run'), source: 'spec:cancelEvalRun "Cancel an ongoing evaluation run."' },
165
+ vendor(['queued'], 'in_progress', EVAL_DOCS),
166
+ vendor(['in_progress'], 'completed', EVAL_DOCS),
167
+ // OpenAI fails a run whose data source or model errors; the twin grades with a stub, which never does
168
+ ],
169
+ };
170
+ /** A file attached to a store as OpenAI shows it: its id is the file's, not the twin's composite key. */
171
+ export function vectorStoreFileView(body, subject) {
172
+ return { id: subject.id.split('::')[1] ?? subject.id, object: 'vector_store.file', vector_store_id: body.vector_store_id, created_at: body.created_at, status: body.status, usage_bytes: body.usage_bytes ?? 0, last_error: body.last_error ?? null, ...(body.attributes ? { attributes: body.attributes } : {}) };
173
+ }
174
+ /** OpenAI's list order: newest first by creation time. */
175
+ const NEWEST = { field: 'created_at', direction: 'desc' };
176
+ /** OpenAI's deletion answer names the deleted object's own type (`vector_store.deleted`). */
177
+ const deletedAs = (object) => ({ id: '{id}', object, deleted: true });
178
+ const underStore = { param: 'vector_store_id', field: 'vector_store_id', resource: 'VectorStoreObject' };
179
+ const underThread = { param: 'thread_id', field: 'thread_id', resource: 'ThreadObject' };
180
+ export const manifest = {
181
+ vendor: 'openai',
182
+ service: 'openai',
183
+ body: {},
184
+ ids: { template: '{prefix}-twin-{n}' },
185
+ // The screens people reach (docs/contributing/architecture.md, "Screens"): a project's secret keys are made on the
186
+ // dashboard's API keys page, never through the API, which only lists, reads and deletes them.
187
+ screens: [
188
+ {
189
+ id: 'api-keys', kind: 'workspace', host: 'platform.openai.com', path: '/settings/{project}/api-keys', status: 'done',
190
+ demand: 'every application that calls the API runs on a key a person made on this page',
191
+ controls: ['Name', 'Permissions', 'Create secret key', 'Revoke key'],
192
+ source: 'https://platform.openai.com/docs/api-reference/project-api-keys',
193
+ },
194
+ ],
195
+ time: 'unix',
196
+ error: { error: { message: '{message}', type: '{kind}', param: '{param}', code: '{code}' } },
197
+ defaultKind: 'invalid_request_error',
198
+ readOnly: { status: 405, code: 'method_not_allowed', message: 'twin is read-only; omit readOnly to accept writes' },
199
+ notFound: { status: 404, message: "No such {object}: '{id}'" },
200
+ list: {
201
+ style: 'envelope',
202
+ envelope: { object: 'list', data: '{data}', has_more: '{has_more}', first_id: '{first_id}', last_id: '{last_id}' },
203
+ limit: { param: 'limit', default: 20, max: 100 },
204
+ after: 'after',
205
+ before: 'before',
206
+ unknownCursor: 'end',
207
+ },
208
+ deleted: { id: '{id}', object: '{object}', deleted: true },
209
+ // OpenAI requires a bearer key on every request. The twin cannot check real keys, so it answers
210
+ // the checkable failures: none, or a key it reserves as invalid.
211
+ auth: {
212
+ header: 'authorization',
213
+ scheme: 'Bearer',
214
+ gateWhenAbsent: true,
215
+ missing: { status: 401, code: 'invalid_api_key', message: "You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY)." },
216
+ invalidKeys: ['sk-invalid', 'invalid'],
217
+ invalid: { status: 401, code: 'invalid_api_key', message: 'Incorrect API key provided. You can find your API key at https://platform.openai.com/account/api-keys.' },
218
+ },
219
+ answerHeaders: { 'x-request-id': 'req_twin' },
220
+ sse: { named: false, done: '[DONE]' },
221
+ // a response streams named events (`event: response.created`) and ends with `response.completed`, no sentinel
222
+ // (https://platform.openai.com/docs/api-reference/responses-streaming; the reference's Streaming example)
223
+ // a streamed transcription is `data:` events ending with `transcript.text.done`, no sentinel (the reference's
224
+ // Streaming transcription example); a streamed image is named events ending with its `completed` event
225
+ // (https://platform.openai.com/docs/api-reference/images-streaming)
226
+ streamFor: { createResponse: { named: true }, beta_createResponse: { named: true }, createTranscription: { named: false }, createImage: { named: true }, createImageEdit: { named: true } },
227
+ // operations of declared resources the twin does not model: OpenAI's unknown-URL answer, not the core's
228
+ unmodeled: [
229
+ 'updateChatCompletion',
230
+ 'modifyVectorStore', 'updateVectorStoreFileAttributes',
231
+ 'modifyMessage', 'deleteMessage', 'modifyRun',
232
+ 'updateEval', 'deleteEval', 'deleteEvalRun', 'getEvalRunOutputItem',
233
+ ],
234
+ // a search is a POST that only reads: a read-only twin answers it
235
+ reads: ['searchVectorStore'],
236
+ resources: {
237
+ // the catalog is static data and fine-tuned models are read off their jobs; a row here is only
238
+ // a deletion (semantics/models.ts serves every operation)
239
+ Model: { storedAs: 'model', idPrefix: 'model', notFound: { code: 'model_not_found', message: "The model '{id}' does not exist" } },
240
+ // `status` is deprecated on a File (always `processed` here) and `purpose` is what it is for:
241
+ // neither moves (https://platform.openai.com/docs/api-reference/files/object)
242
+ OpenAIFile: { storedAs: 'file', idPrefix: 'file', notFound: 'No such File object: {id}', notState: ['purpose', 'status'], order: NEWEST },
243
+ FineTuningJob: { storedAs: 'fine_tuning_job', idPrefix: 'ftjob', notFound: 'No such fine-tuning job: {id}', state: { status: fineTuningJobStatus }, order: NEWEST },
244
+ // read off their job, never stored (semantics/fine-tuning.ts)
245
+ FineTuningJobEvent: { idPrefix: 'ftevent', notState: ['level', 'type'] },
246
+ FineTuningJobCheckpoint: { idPrefix: 'ftckpt' },
247
+ // a store and what it holds are born completed (the twin embeds nothing)
248
+ VectorStoreObject: { storedAs: 'vector_store', idPrefix: 'vs', notFound: 'No such vector store: {id}', deleted: deletedAs('vector_store.deleted'), state: { status: vectorStoreStatus }, order: NEWEST },
249
+ // one file may sit in several stores, so an attached file is keyed by both and shown by the file's id
250
+ VectorStoreFileObject: {
251
+ storedAs: 'vector_store_file',
252
+ idPrefix: 'vsf',
253
+ parent: underStore,
254
+ key: '{vector_store_id}::{file_id}',
255
+ view: vectorStoreFileView,
256
+ state: { status: vectorStoreFileStatus('spec:/components/schemas/VectorStoreFileObject/properties/status "The status of the vector store file, which can be either `in_progress`, `completed`, `cancelled`, or `failed`."') },
257
+ },
258
+ VectorStoreFileBatchObject: {
259
+ storedAs: 'vector_store_file_batch',
260
+ idPrefix: 'vsfb',
261
+ notFound: 'No such file batch: {id}',
262
+ parent: underStore,
263
+ state: { status: vectorStoreFileStatus('spec:/components/schemas/VectorStoreFileBatchObject/properties/status "The status of the vector store files batch, which can be either `in_progress`, `completed`, `cancelled` or `failed`."', notInFlight('a vector store file batch')) },
264
+ },
265
+ // every call is recorded; only a `store: true` one reads back (semantics/chat-completions.ts)
266
+ CreateChatCompletionResponse: {
267
+ storedAs: 'chat_completion',
268
+ idPrefix: 'chatcmpl',
269
+ readableWhen: { _stored: true },
270
+ notFound: "No chat completion found with id '{id}'.",
271
+ deleted: deletedAs('chat.completion.deleted'),
272
+ order: { field: 'created', direction: 'desc' },
273
+ },
274
+ // a stored response and its input items (semantics/responses.ts); one tree type for both surfaces. Its deletion
275
+ // answers `"object": "response"` (the reference's delete example: https://platform.openai.com/docs/api-reference/responses/delete)
276
+ Response: { storedAs: 'response', idPrefix: 'resp', notFound: "Response with id '{id}' not found.", deleted: deletedAs('response'), state: { status: responseStatus('') } },
277
+ BetaResponse: { storedAs: 'response', idPrefix: 'resp', notFound: "Response with id '{id}' not found.", deleted: deletedAs('response'), state: { status: responseStatus('beta_') } },
278
+ // the items live inside their response, never stored on their own: who wrote one, where a tool
279
+ // call ran, and how far generation got are what it is, and the twin's are whole
280
+ ItemResource: { idPrefix: 'item', notState: ['execution', 'role', 'status'] },
281
+ BetaItemResource: { idPrefix: 'item', notState: ['execution', 'role', 'status'] },
282
+ // the Assistants API (semantics/assistants.ts); messages and runs live under their thread
283
+ AssistantObject: { storedAs: 'assistant', idPrefix: 'asst', notFound: "No assistant found with id '{id}'.", deleted: deletedAs('assistant.deleted'), order: NEWEST },
284
+ ThreadObject: { storedAs: 'thread', idPrefix: 'thread', notFound: "No thread found with id '{id}'.", deleted: deletedAs('thread.deleted') },
285
+ // a message's role is who wrote it and its status is not modeled (every message is whole)
286
+ MessageObject: { storedAs: 'message', idPrefix: 'msg', notFound: "No message found with id '{id}'.", parent: underThread, notState: ['role', 'status'], order: NEWEST },
287
+ RunObject: { storedAs: 'run', idPrefix: 'run', notFound: "No run found with id '{id}'.", parent: underThread, state: { status: runStatus }, order: NEWEST },
288
+ // a run's steps are read off the run, never stored, so neither field moves on its own
289
+ RunStepObject: { idPrefix: 'step', notState: ['status', 'type'] },
290
+ // the Admin API (semantics/organization.ts); residency and a key's project access are settings
291
+ Project: { storedAs: 'project', idPrefix: 'proj', notFound: 'Project {id} not found', state: { status: projectStatus }, notState: ['residency'], order: NEWEST },
292
+ ProjectApiKey: {
293
+ storedAs: 'api_key',
294
+ idPrefix: 'key',
295
+ notFound: 'API key {id} not found',
296
+ parent: { param: 'project_id', field: '_project_id', resource: 'Project' },
297
+ deleted: deletedAs('organization.project.api_key.deleted'),
298
+ notState: ['owner_project_access'],
299
+ order: NEWEST,
300
+ },
301
+ // computed from the recorded usage, never stored
302
+ UsageTimeBucket: { idPrefix: 'bucket' },
303
+ // the Evals API (semantics/evals.ts); a run lives under its eval, its output items are read off it
304
+ Eval: { storedAs: 'eval', idPrefix: 'eval', notFound: 'Eval {id} not found', order: NEWEST },
305
+ EvalRun: { storedAs: 'eval_run', idPrefix: 'evalrun', notFound: 'Eval run {id} not found', parent: { param: 'eval_id', field: 'eval_id', resource: 'Eval' }, state: { status: evalRunStatus }, order: NEWEST },
306
+ // an output item's status is its grade (pass or fail), not a lifecycle
307
+ EvalRunOutputItem: { idPrefix: 'evalitem', notState: ['status'] },
308
+ // code-interpreter sandboxes (semantics/containers.ts); a file lives under its container, and a
309
+ // container's memory_limit is a setting
310
+ ContainerResource: { storedAs: 'container', idPrefix: 'cntr', notFound: 'Container {id} not found', deleted: deletedAs('container.deleted'), state: { status: containerStatus }, notState: ['memory_limit'], order: NEWEST },
311
+ ContainerFileResource: {
312
+ storedAs: 'container_file',
313
+ idPrefix: 'cfile',
314
+ notFound: 'Container file {id} not found',
315
+ parent: { param: 'container_id', field: 'container_id', resource: 'ContainerResource' },
316
+ deleted: deletedAs('container.file.deleted'),
317
+ order: NEWEST,
318
+ },
319
+ Batch: { storedAs: 'batch', idPrefix: 'batch', notFound: 'No such Batch object: {id}', state: { status: batchStatus }, order: NEWEST },
320
+ // a large file sent in parts (semantics/uploads.ts); the spec names no resource for it
321
+ Upload: { storedAs: 'upload', idPrefix: 'upload', notFound: 'No such Upload object: {id}', state: { status: uploadStatus } },
322
+ },
323
+ };
@@ -0,0 +1,53 @@
1
+ import { RateBudget, type RateBudgetDeclaration, type RateBudgetOptions, type RateBudgetReservation, type RateBudgetSnapshot } from '@volter/world-core';
2
+ /** Rolling window, in ms. Spend older than this is pruned. */
3
+ export declare const OPENAI_BUDGET_WINDOW_MS = 60000;
4
+ /**
5
+ * Weighted units allowed inside one window. 60/60s at `defaultWeight` 2 = 30 calls a minute —
6
+ * EXACTLY the kernel's undeclared fallback, because OpenAI publishes no scalar that would justify
7
+ * more. See the header.
8
+ */
9
+ export declare const OPENAI_BUDGET_CEILING = 60;
10
+ /** Seconds. A `retry-after` above this means the key is throttled hard — fail loudly, don't sleep. */
11
+ export declare const OPENAI_BUDGET_MAX_RETRY_AFTER_S = 300;
12
+ /** Per-call cost, keyed by `"<METHOD> <path>"`. See the header for what is documented vs. judged. */
13
+ export declare const OPENAI_CALL_WEIGHTS: {
14
+ /** `/v1/chat/completions`, `/v1/responses`, `/v1/embeddings`, `/v1/images/*`, `/v1/audio/*` —
15
+ * token/compute-metered, where TPM rather than RPM is the binding limit. */
16
+ readonly inference: 5;
17
+ /** `POST /v1/vector_stores/:id/files` — documented 300 RPM per store, and a per-file fan-out. */
18
+ readonly ingest: 4;
19
+ /** Everything else: file/batch/fine-tune/vector-store list, retrieve, create, cancel, delete. */
20
+ readonly other: 2;
21
+ };
22
+ /** THE PACK'S DECLARATION — pure data, the only OpenAI-specific thing in the whole budget. */
23
+ export declare const OPENAI_RATE_BUDGET: RateBudgetDeclaration;
24
+ /**
25
+ * Price one call. The key is `"<METHOD> <path>"` with the query string split off, so a rule can
26
+ * price by method (a write is not a read) without the kernel knowing anything about OpenAI. An
27
+ * unclassified endpoint still costs `defaultWeight` — nothing is ever free.
28
+ */
29
+ export declare function openaiCallWeight(method: string, path: string): number;
30
+ /** Where OpenAI's ledger lives. Token-keyed and cwd-independent by default (the limit is per
31
+ * organization/project, i.e. per key, so a cwd-scoped ledger would hand the same key a fresh
32
+ * allowance in every checkout, worktree and CI matrix leg); pass `root` for world-scoped accounting. */
33
+ export declare function openaiBudgetPath(opts?: {
34
+ root?: string;
35
+ token?: string;
36
+ } | string): string;
37
+ /** Construction options for OpenAI's budget. The vendor is fixed; everything else may only TIGHTEN. */
38
+ export type OpenAIBudgetOptions = Omit<RateBudgetOptions, 'vendor'>;
39
+ /**
40
+ * OpenAI's budget — the shared kernel guard bound to this vendor's declaration. A real subclass,
41
+ * not an alias, so `budget instanceof OpenAIBudget` in `liveOpenAIExecute` means "a budget that
42
+ * accounts against OPENAI's ledger under OPENAI's ceiling": another vendor's `RateBudget` (with its
43
+ * own, possibly larger, ceiling) is NOT assignable there.
44
+ */
45
+ export declare class OpenAIBudget extends RateBudget {
46
+ constructor(opts?: OpenAIBudgetOptions);
47
+ }
48
+ /** The typed refusal. One error class shared with every other vendor's budget; `err.vendor` says
49
+ * which one refused, and `err.kind` says why. */
50
+ export { RateBudgetError as OpenAIBudgetError } from '@volter/world-core';
51
+ export type { RateBudgetErrorKind as OpenAIBudgetErrorKind } from '@volter/world-core';
52
+ export type OpenAIBudgetReservation = RateBudgetReservation;
53
+ export type OpenAIBudgetSnapshot = RateBudgetSnapshot;