@tessar/openai 0.0.0-stage → 0.1.0-alpha.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.
package/README.md CHANGED
@@ -1,3 +1,37 @@
1
- # Temporary Holding Version
1
+ # @tessar/openai
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ OpenAI Responses provider and automatic model metadata integration for Tessar.
4
+ Requires Node 24.14 or newer and uses the official OpenAI SDK.
5
+
6
+ ```sh
7
+ npm install @tessar/core@next @tessar/openai@next
8
+ ```
9
+
10
+ ```ts
11
+ import { Agent, Controller, HumanMessage } from "@tessar/core";
12
+ import { OpenAIPlugin } from "@tessar/openai";
13
+
14
+ const agent = new Agent({
15
+ id: "assistant",
16
+ model: { providerId: "openai", modelId: process.env.OPENAI_MODEL! },
17
+ });
18
+ const controller = new Controller({
19
+ id: "application",
20
+ agent,
21
+ plugins: [new OpenAIPlugin({ apiKey: process.env.OPENAI_API_KEY! })],
22
+ });
23
+
24
+ try {
25
+ await controller.initialize();
26
+ const result = await agent.generate({ input: new HumanMessage("Hello") });
27
+ console.log(result.output);
28
+ } finally {
29
+ await controller.dispose();
30
+ }
31
+ ```
32
+
33
+ Provider SDK exceptions retain their original identity. The adapter disables
34
+ implicit SDK retries. Model metadata may be incomplete and carries provenance.
35
+
36
+ This is an alpha release. See the
37
+ [repository](https://github.com/hphucdev-04/tessar) for complete contracts.
@@ -0,0 +1,19 @@
1
+ import OpenAI from "openai";
2
+ import { type ModelAdapter, type ModelChunk, type ModelRef, type ModelRequest } from "@tessar/core";
3
+ export interface OpenAIOptions {
4
+ apiKey: string;
5
+ baseURL?: string;
6
+ providerId?: string;
7
+ fetch?: typeof fetch;
8
+ metadataPartition?: string;
9
+ }
10
+ export declare function createClient(options: OpenAIOptions): OpenAI;
11
+ export declare class OpenAIAdapter implements ModelAdapter {
12
+ readonly ref: ModelRef;
13
+ private readonly client;
14
+ constructor(options: OpenAIOptions, ref: ModelRef, client?: OpenAI);
15
+ validate(request: ModelRequest): void;
16
+ stream(request: ModelRequest, context: {
17
+ signal: AbortSignal;
18
+ }): AsyncIterable<ModelChunk>;
19
+ }
@@ -0,0 +1,127 @@
1
+ import OpenAI, { OpenAIError } from "openai";
2
+ import { errorInfo, MessageCodec, fail, normalizeUsage, } from "@tessar/core";
3
+ import { decodeOutput, encodeInput } from "./codec.js";
4
+ export function createClient(options) {
5
+ return new OpenAI({
6
+ apiKey: options.apiKey,
7
+ baseURL: options.baseURL,
8
+ fetch: options.fetch,
9
+ maxRetries: 0,
10
+ });
11
+ }
12
+ function usage(value) {
13
+ return normalizeUsage({
14
+ inputTokens: value?.input_tokens,
15
+ outputTokens: value?.output_tokens,
16
+ totalTokens: value?.total_tokens,
17
+ cacheReadInputTokens: value?.input_tokens_details?.cached_tokens,
18
+ cacheWriteInputTokens: value?.input_tokens_details?.cache_write_tokens,
19
+ reasoningOutputTokens: value?.output_tokens_details?.reasoning_tokens,
20
+ uncachedInputTokens: value?.input_tokens !== undefined &&
21
+ value?.input_tokens_details?.cached_tokens !== undefined
22
+ ? Math.max(0, value.input_tokens - value.input_tokens_details.cached_tokens)
23
+ : null,
24
+ }, value ? JSON.parse(JSON.stringify(value)) : null);
25
+ }
26
+ export class OpenAIAdapter {
27
+ ref;
28
+ client;
29
+ constructor(options, ref, client) {
30
+ this.ref = ref;
31
+ this.client = client ?? createClient(options);
32
+ }
33
+ validate(request) {
34
+ try {
35
+ if (request.model.providerId !== this.ref.providerId ||
36
+ request.model.modelId !== this.ref.modelId)
37
+ fail("UnsupportedContext", "Model identity mismatch");
38
+ encodeInput(request);
39
+ }
40
+ catch (error) {
41
+ errorInfo(error, { source: "tessar", ...this.ref });
42
+ throw error;
43
+ }
44
+ }
45
+ async *stream(request, context) {
46
+ this.validate(request);
47
+ context.signal.throwIfAborted();
48
+ const failure = (message, code) => {
49
+ const error = Object.assign(new Error(message), { code });
50
+ errorInfo(error, { source: "provider", ...this.ref });
51
+ return error;
52
+ };
53
+ try {
54
+ const stream = await this.client.responses.create({
55
+ model: this.ref.modelId,
56
+ instructions: request.instructions.sections
57
+ .map((s) => s.content)
58
+ .join("\n\n"),
59
+ input: encodeInput(request),
60
+ tools: request.tools.map((t) => ({
61
+ type: "function",
62
+ name: t.name,
63
+ description: t.description,
64
+ parameters: t.inputSchema,
65
+ strict: false,
66
+ })),
67
+ include: ["reasoning.encrypted_content"],
68
+ store: false,
69
+ stream: true,
70
+ }, { signal: context.signal });
71
+ let terminal = false;
72
+ for await (const event of stream) {
73
+ context.signal.throwIfAborted();
74
+ switch (event.type) {
75
+ case "response.output_text.delta":
76
+ yield {
77
+ type: "message-delta",
78
+ messageId: event.item_id,
79
+ partId: event.item_id + ":" + event.content_index,
80
+ partKind: "text",
81
+ delta: event.delta,
82
+ };
83
+ break;
84
+ case "response.reasoning_summary_text.delta":
85
+ yield {
86
+ type: "message-delta",
87
+ messageId: event.item_id,
88
+ partId: event.item_id + ":summary:" + event.summary_index,
89
+ partKind: "reasoning",
90
+ delta: event.delta,
91
+ };
92
+ break;
93
+ case "response.completed": {
94
+ terminal = true;
95
+ const normalized = usage(event.response.usage);
96
+ yield { type: "usage", usage: normalized };
97
+ yield {
98
+ type: "response",
99
+ response: {
100
+ message: MessageCodec.encode(decodeOutput(event.response.output, this.ref, event.response.id)),
101
+ usage: normalized,
102
+ finishReason: "completed",
103
+ providerRequestId: event.response.id,
104
+ },
105
+ };
106
+ break;
107
+ }
108
+ case "response.incomplete":
109
+ case "response.failed":
110
+ yield { type: "usage", usage: usage(event.response.usage) };
111
+ throw failure(event.response.error?.message ?? "OpenAI response did not complete", event.response.error?.code ?? "ProviderIncomplete");
112
+ case "error":
113
+ throw failure(event.message, event.code ?? "ProviderError");
114
+ }
115
+ }
116
+ if (!terminal)
117
+ throw failure("OpenAI stream ended before completion", "ProviderIncomplete");
118
+ }
119
+ catch (error) {
120
+ if (context.signal.aborted)
121
+ throw context.signal.reason;
122
+ errorInfo(error, { source: error instanceof OpenAIError ? "provider" : "tessar", ...this.ref });
123
+ throw error;
124
+ }
125
+ }
126
+ }
127
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { AssistantMessage, type ModelRef, type ModelRequest } from "@tessar/core";
2
+ import type { ResponseInput } from "openai/resources/responses/responses";
3
+ export declare function encodeInput(request: ModelRequest): ResponseInput;
4
+ export declare function decodeOutput(items: readonly unknown[], ref: ModelRef, responseId: string): AssistantMessage;
package/dist/codec.js ADDED
@@ -0,0 +1,145 @@
1
+ import { AssistantMessage, TessarError, fail, assertJson, } from "@tessar/core";
2
+ function continuity(value) {
3
+ if (!value ||
4
+ typeof value !== "object" ||
5
+ !("codec" in value) ||
6
+ value.codec !== "openai.responses")
7
+ return null;
8
+ const data = value;
9
+ if (data.version !== 1 || !Array.isArray(data.items))
10
+ fail("UnsupportedContext", "Unknown OpenAI continuity version");
11
+ return data;
12
+ }
13
+ export function encodeInput(request) {
14
+ const input = [];
15
+ for (const message of request.messages) {
16
+ const state = continuity(message.providerState);
17
+ if (state) {
18
+ if (state.providerId !== request.model.providerId ||
19
+ state.modelId !== request.model.modelId)
20
+ fail("UnsupportedContext", "Opaque OpenAI context requires its original model");
21
+ input.push(...state.items);
22
+ continue;
23
+ }
24
+ if (message.providerState !== undefined ||
25
+ message.content.some((p) => p.type === "reasoning"))
26
+ fail("UnsupportedContext", "Unsupported provider continuity");
27
+ if (message.role === "tool") {
28
+ if (message.content.some((p) => p.type !== "text"))
29
+ fail("UnsupportedContext", "OpenAI tool output currently requires text parts");
30
+ input.push({
31
+ type: "function_call_output",
32
+ call_id: message.toolCallId,
33
+ output: message.content
34
+ .map((p) => (p.type === "text" ? p.text : ""))
35
+ .join(""),
36
+ });
37
+ continue;
38
+ }
39
+ const role = message.role;
40
+ let content = [];
41
+ const flush = () => {
42
+ if (content.length) {
43
+ input.push({ role, content });
44
+ content = [];
45
+ }
46
+ };
47
+ for (const part of message.content) {
48
+ switch (part.type) {
49
+ case "text":
50
+ content.push(message.role === "assistant"
51
+ ? { type: "output_text", text: part.text, annotations: [] }
52
+ : { type: "input_text", text: part.text });
53
+ break;
54
+ case "tool-call":
55
+ if (message.role !== "assistant")
56
+ fail("UnsupportedContext", "Tool calls require assistant role");
57
+ flush();
58
+ input.push({
59
+ type: "function_call",
60
+ call_id: part.toolCallId,
61
+ name: part.name,
62
+ arguments: JSON.stringify(part.arguments),
63
+ });
64
+ break;
65
+ case "image":
66
+ if (message.role !== "user")
67
+ fail("UnsupportedContext", "Image input requires user role");
68
+ content.push({
69
+ type: "input_image",
70
+ image_url: part.data.startsWith("https:") || part.data.startsWith("data:")
71
+ ? part.data
72
+ : `data:${part.mediaType};base64,${part.data}`,
73
+ detail: "auto",
74
+ });
75
+ break;
76
+ case "file":
77
+ if (message.role !== "user")
78
+ fail("UnsupportedContext", "File input requires user role");
79
+ content.push({
80
+ type: "input_file",
81
+ file_data: part.data,
82
+ filename: message.id,
83
+ });
84
+ break;
85
+ default:
86
+ fail("UnsupportedContext", "Unsupported OpenAI message part");
87
+ }
88
+ }
89
+ flush();
90
+ }
91
+ return input;
92
+ }
93
+ export function decodeOutput(items, ref, responseId) {
94
+ assertJson(items);
95
+ const parts = [];
96
+ for (const raw of items) {
97
+ const item = raw;
98
+ switch (item.type) {
99
+ case "message":
100
+ for (const content of item.content) {
101
+ if (content.type === "output_text")
102
+ parts.push({ type: "text", text: content.text });
103
+ else if (content.type === "refusal")
104
+ parts.push({ type: "text", text: content.refusal });
105
+ else
106
+ fail("UnsupportedResponse", "Unsupported OpenAI output content");
107
+ }
108
+ break;
109
+ case "reasoning":
110
+ for (const summary of item.summary ?? [])
111
+ parts.push({ type: "reasoning", text: summary.text });
112
+ break;
113
+ case "function_call": {
114
+ let args;
115
+ try {
116
+ args = JSON.parse(item.arguments);
117
+ }
118
+ catch {
119
+ throw new TessarError("ProviderResponse", "Invalid OpenAI function arguments");
120
+ }
121
+ if (!args || typeof args !== "object" || Array.isArray(args))
122
+ fail("ProviderResponse", "Function arguments must be an object");
123
+ parts.push({
124
+ type: "tool-call",
125
+ toolCallId: item.call_id,
126
+ name: item.name,
127
+ arguments: args,
128
+ });
129
+ break;
130
+ }
131
+ default:
132
+ fail("UnsupportedResponse", "Unsupported OpenAI output item");
133
+ }
134
+ }
135
+ return new AssistantMessage(parts, {
136
+ id: responseId,
137
+ providerState: {
138
+ codec: "openai.responses",
139
+ version: 1,
140
+ ...ref,
141
+ items: items,
142
+ },
143
+ });
144
+ }
145
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../src/codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { OpenAIAdapter, type OpenAIOptions } from "./adapter.js";
2
+ export { OpenAIPlugin } from "./plugin.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { OpenAIAdapter } from "./adapter.js";
2
+ export { OpenAIPlugin } from "./plugin.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAoB,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type OpenAI from "openai";
2
+ import type { MetadataResolver } from "@tessar/core";
3
+ export declare function metadataResolver(client: OpenAI): MetadataResolver;
@@ -0,0 +1,9 @@
1
+ export function metadataResolver(client) {
2
+ return {
3
+ async resolve(ref, options) {
4
+ await client.models.retrieve(ref.modelId, { signal: options.signal });
5
+ return {};
6
+ },
7
+ };
8
+ }
9
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO;YACxB,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YACtE,OAAO,EAAE,CAAC;QACZ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Plugin, PluginContext } from "@tessar/core";
2
+ import { type OpenAIOptions } from "./adapter.js";
3
+ export declare class OpenAIPlugin implements Plugin {
4
+ readonly id: string;
5
+ private readonly providerId;
6
+ private readonly options;
7
+ constructor(options: OpenAIOptions);
8
+ setup(tessar: PluginContext): void;
9
+ }
package/dist/plugin.js ADDED
@@ -0,0 +1,29 @@
1
+ import { OpenAIAdapter, createClient } from "./adapter.js";
2
+ import { metadataResolver } from "./metadata.js";
3
+ export class OpenAIPlugin {
4
+ id;
5
+ providerId;
6
+ options;
7
+ constructor(options) {
8
+ this.options = options;
9
+ this.providerId = options.providerId ?? "openai";
10
+ this.id = "provider." + this.providerId;
11
+ }
12
+ setup(tessar) {
13
+ const options = this.options, id = this.providerId;
14
+ const client = createClient(options);
15
+ tessar.models.registerProvider({
16
+ id,
17
+ endpoint: options.baseURL ?? "https://api.openai.com/v1",
18
+ metadataPartition: options.metadataPartition,
19
+ metadata: metadataResolver(client),
20
+ catalogModelRef: (ref) => !options.baseURL ||
21
+ options.baseURL.replace(/\/$/, "") === "https://api.openai.com/v1"
22
+ ? { providerId: "openai", modelId: ref.modelId }
23
+ : null,
24
+ catalogMappingVersion: 1,
25
+ create: (modelId) => new OpenAIAdapter(options, { providerId: id, modelId }, client),
26
+ });
27
+ }
28
+ }
29
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAsB,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,MAAM,OAAO,YAAY;IACd,EAAE,CAAS;IACH,UAAU,CAAS;IACnB,OAAO,CAAgB;IAExC,YAAY,OAAsB;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC;QACjD,IAAI,CAAC,EAAE,GAAG,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,MAAqB;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QACnD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAC7B,EAAE;YACF,QAAQ,EAAE,OAAO,CAAC,OAAO,IAAI,2BAA2B;YACxD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;YAC5C,QAAQ,EAAE,gBAAgB,CAAC,MAAM,CAAC;YAClC,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE,CACvB,CAAC,OAAO,CAAC,OAAO;gBAChB,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,2BAA2B;gBAChE,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;gBAChD,CAAC,CAAC,IAAI;YACV,qBAAqB,EAAE,CAAC;YACxB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAClB,IAAI,aAAa,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,CAAC;SAClE,CAAC,CAAC;IACL,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "@tessar/openai",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "OpenAI Responses provider and model metadata integration for Tessar.",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=24.14.0"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/hphucdev-04/tessar.git",
21
+ "directory": "packages/openai"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public",
25
+ "registry": "https://registry.npmjs.org/"
26
+ },
27
+ "dependencies": {
28
+ "openai": "7.34.0",
29
+ "@tessar/core": "0.1.0-alpha.0"
30
+ },
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.json",
33
+ "typecheck": "tsc --noEmit -p tsconfig.json"
34
+ }
6
35
  }