@volter/twin-openai 2.0.1 → 2.0.3

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.
@@ -10,7 +10,7 @@
10
10
  // The surface is a plain `fetch` (`createOpenAITwinFetch`) and the SERVER is one line of
11
11
  // `Bun.serve` around it — see that factory's docstring for why (a serverless entry has no
12
12
  // port to bind, so it mounts the fetch in-process).
13
- import { bindSemantics, coreFor, createDerivedFetch, crossCutting, semanticsContext, serveHttp, vendorError } from '@volter/world-core';
13
+ import { bindSemantics, coreFor, createDerivedFetch, crossCutting, derivedRequestScopes, runAsVendorMove, semanticsContext, serveHttp, vendorError } from '@volter/world-core';
14
14
  import surface from './generated/surface.gen.json' with { type: 'json' };
15
15
  import { manifest } from "./manifest.js";
16
16
  import { openaiSemantics } from "./semantics/index.js";
@@ -89,21 +89,24 @@ export function createOpenAITwinFetch(options) {
89
89
  const useKey = projectKeyUse(scope);
90
90
  // and a read of the files observes the work whose outputs are files (a batch's output, a fine-tuning job's results)
91
91
  // first, as a read of that batch or job does: the files a read lists never depend on which other read came before it
92
- const catchUp = async (request) => {
92
+ // time's moves and a key's recorded use are OpenAI's own, not the caller's: they land under a read-only request
93
+ // too (runAsVendorMove)
94
+ const catchUp = (request) => runAsVendorMove(async () => {
93
95
  const ctx = await semanticsContext(manifest, new Request(request.url), filesClock, scope);
94
96
  await expireFiles(ctx);
95
97
  if (request.method === 'GET' && /^\/v1\/files(\/|$)/.test(new URL(request.url).pathname))
96
98
  for (const observe of [observeBatches, observeJobs])
97
99
  await observe(ctx);
98
- };
99
- return Object.assign(async (request) => {
100
+ });
101
+ // a read-only request (x-volter-read-only) writes nothing, answered with OpenAI's read-only error
102
+ return derivedRequestScopes(manifest, Object.assign(async (request) => {
100
103
  const opened = door(request);
101
104
  if (opened)
102
105
  return opened;
103
106
  if (!readOnly)
104
107
  await catchUp(request);
105
108
  if (!readOnly) {
106
- const refused = await useKey(request);
109
+ const refused = await runAsVendorMove(() => useKey(request));
107
110
  if (refused)
108
111
  return refused;
109
112
  }
@@ -114,7 +117,7 @@ export function createOpenAITwinFetch(options) {
114
117
  return page;
115
118
  }
116
119
  return handle(request);
117
- }, { owners: inner.owners });
120
+ }, { owners: inner.owners }));
118
121
  }
119
122
  export async function createOpenAITwinServer(options) {
120
123
  const server = await serveHttp({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-openai",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Local OpenAI twin — a faithful, stateful local OpenAI API your real `openai` SDK talks to unmodified. The model is stubbed (deterministic) and embeddings are deterministic pseudo-vectors, but the protocol envelope (chat completions/streaming/tool_calls, the Responses API, embeddings, models, files, batches, moderations, fine-tuning, vector stores) is vendor-faithful. Built on @volter/world-core.",
5
5
  "keywords": [
6
6
  "twin",
@@ -54,10 +54,10 @@
54
54
  "postpack": "node ../../../scripts/publish/prepare-publish.mjs postpack"
55
55
  },
56
56
  "peerDependencies": {
57
- "@volter/world-core": "2.0.1"
57
+ "@volter/world-core": "2.0.3"
58
58
  },
59
59
  "devDependencies": {
60
- "@volter/world-core": "2.0.1",
60
+ "@volter/world-core": "2.0.3",
61
61
  "@volter/world-tooling": "0.1.0",
62
62
  "openai": "^4.104.0",
63
63
  "@types/bun": "^1.2.20",
@@ -68,6 +68,6 @@
68
68
  "node": ">=22.3"
69
69
  },
70
70
  "dependencies": {
71
- "@volter/world-ui": "0.1.1"
71
+ "@volter/world-ui": "0.1.3"
72
72
  }
73
73
  }
@@ -10,7 +10,7 @@
10
10
  // The surface is a plain `fetch` (`createOpenAITwinFetch`) and the SERVER is one line of
11
11
  // `Bun.serve` around it — see that factory's docstring for why (a serverless entry has no
12
12
  // port to bind, so it mounts the fetch in-process).
13
- import { bindSemantics, coreFor, createDerivedFetch, crossCutting, semanticsContext, serveHttp, vendorError } from '@volter/world-core';
13
+ import { bindSemantics, coreFor, createDerivedFetch, crossCutting, derivedRequestScopes, runAsVendorMove, semanticsContext, serveHttp, vendorError } from '@volter/world-core';
14
14
  import surface from './generated/surface.gen.json' with { type: 'json' };
15
15
  import { manifest } from './manifest.ts';
16
16
  import { openaiSemantics } from './semantics/index.ts';
@@ -99,19 +99,22 @@ export function createOpenAITwinFetch(options: OpenAITwinFetchOptions): (request
99
99
  const useKey = projectKeyUse(scope);
100
100
  // and a read of the files observes the work whose outputs are files (a batch's output, a fine-tuning job's results)
101
101
  // first, as a read of that batch or job does: the files a read lists never depend on which other read came before it
102
- const catchUp = async (request: Request): Promise<void> => {
102
+ // time's moves and a key's recorded use are OpenAI's own, not the caller's: they land under a read-only request
103
+ // too (runAsVendorMove)
104
+ const catchUp = (request: Request): Promise<void> => runAsVendorMove(async () => {
103
105
  const ctx = await semanticsContext(manifest, new Request(request.url), filesClock, scope);
104
106
  await expireFiles(ctx);
105
107
  if (request.method === 'GET' && /^\/v1\/files(\/|$)/.test(new URL(request.url).pathname)) for (const observe of [observeBatches, observeJobs]) await observe(ctx);
106
- };
107
- return Object.assign(async (request: Request): Promise<Response> => {
108
+ });
109
+ // a read-only request (x-volter-read-only) writes nothing, answered with OpenAI's read-only error
110
+ return derivedRequestScopes(manifest, Object.assign(async (request: Request): Promise<Response> => {
108
111
  const opened = door(request);
109
112
  if (opened) return opened;
110
113
  if (!readOnly) await catchUp(request);
111
- if (!readOnly) { const refused = await useKey(request); if (refused) return refused; }
114
+ if (!readOnly) { const refused = await runAsVendorMove(() => useKey(request)); if (refused) return refused; }
112
115
  if (!readOnly) for (const screen of screens) { const page = await screen(request); if (page) return page; }
113
116
  return handle(request);
114
- }, { owners: inner.owners });
117
+ }, { owners: inner.owners }));
115
118
  }
116
119
 
117
120
  export async function createOpenAITwinServer(options: { root?: string; port?: number; readOnly?: boolean; scenarioPath?: string }): Promise<{ port: number; stop: () => void }> {