@grafana/sigil-sdk-js 0.0.1

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 (110) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +367 -0
  3. package/dist/client.d.ts +102 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +1502 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/config.d.ts +9 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +190 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/content_capture.d.ts +35 -0
  12. package/dist/content_capture.d.ts.map +1 -0
  13. package/dist/content_capture.js +123 -0
  14. package/dist/content_capture.js.map +1 -0
  15. package/dist/context.d.ts +11 -0
  16. package/dist/context.d.ts.map +1 -0
  17. package/dist/context.js +53 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/exporters/default.d.ts +3 -0
  20. package/dist/exporters/default.d.ts.map +1 -0
  21. package/dist/exporters/default.js +34 -0
  22. package/dist/exporters/default.js.map +1 -0
  23. package/dist/exporters/grpc.d.ts +14 -0
  24. package/dist/exporters/grpc.d.ts.map +1 -0
  25. package/dist/exporters/grpc.js +369 -0
  26. package/dist/exporters/grpc.js.map +1 -0
  27. package/dist/exporters/http.d.ts +8 -0
  28. package/dist/exporters/http.d.ts.map +1 -0
  29. package/dist/exporters/http.js +258 -0
  30. package/dist/exporters/http.js.map +1 -0
  31. package/dist/frameworks/google-adk/index.d.ts +136 -0
  32. package/dist/frameworks/google-adk/index.d.ts.map +1 -0
  33. package/dist/frameworks/google-adk/index.js +509 -0
  34. package/dist/frameworks/google-adk/index.js.map +1 -0
  35. package/dist/frameworks/langchain/index.d.ts +29 -0
  36. package/dist/frameworks/langchain/index.d.ts.map +1 -0
  37. package/dist/frameworks/langchain/index.js +70 -0
  38. package/dist/frameworks/langchain/index.js.map +1 -0
  39. package/dist/frameworks/langgraph/index.d.ts +29 -0
  40. package/dist/frameworks/langgraph/index.d.ts.map +1 -0
  41. package/dist/frameworks/langgraph/index.js +70 -0
  42. package/dist/frameworks/langgraph/index.js.map +1 -0
  43. package/dist/frameworks/llamaindex/index.d.ts +43 -0
  44. package/dist/frameworks/llamaindex/index.d.ts.map +1 -0
  45. package/dist/frameworks/llamaindex/index.js +493 -0
  46. package/dist/frameworks/llamaindex/index.js.map +1 -0
  47. package/dist/frameworks/openai-agents/index.d.ts +33 -0
  48. package/dist/frameworks/openai-agents/index.d.ts.map +1 -0
  49. package/dist/frameworks/openai-agents/index.js +531 -0
  50. package/dist/frameworks/openai-agents/index.js.map +1 -0
  51. package/dist/frameworks/shared.d.ts +57 -0
  52. package/dist/frameworks/shared.d.ts.map +1 -0
  53. package/dist/frameworks/shared.js +1032 -0
  54. package/dist/frameworks/shared.js.map +1 -0
  55. package/dist/frameworks/vercel-ai-sdk/hooks.d.ts +18 -0
  56. package/dist/frameworks/vercel-ai-sdk/hooks.d.ts.map +1 -0
  57. package/dist/frameworks/vercel-ai-sdk/hooks.js +672 -0
  58. package/dist/frameworks/vercel-ai-sdk/hooks.js.map +1 -0
  59. package/dist/frameworks/vercel-ai-sdk/index.d.ts +8 -0
  60. package/dist/frameworks/vercel-ai-sdk/index.d.ts.map +1 -0
  61. package/dist/frameworks/vercel-ai-sdk/index.js +7 -0
  62. package/dist/frameworks/vercel-ai-sdk/index.js.map +1 -0
  63. package/dist/frameworks/vercel-ai-sdk/mapping.d.ts +49 -0
  64. package/dist/frameworks/vercel-ai-sdk/mapping.d.ts.map +1 -0
  65. package/dist/frameworks/vercel-ai-sdk/mapping.js +660 -0
  66. package/dist/frameworks/vercel-ai-sdk/mapping.js.map +1 -0
  67. package/dist/frameworks/vercel-ai-sdk/types.d.ts +126 -0
  68. package/dist/frameworks/vercel-ai-sdk/types.d.ts.map +1 -0
  69. package/dist/frameworks/vercel-ai-sdk/types.js +2 -0
  70. package/dist/frameworks/vercel-ai-sdk/types.js.map +1 -0
  71. package/dist/index.d.ts +12 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +12 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/providers/anthropic.d.ts +35 -0
  76. package/dist/providers/anthropic.d.ts.map +1 -0
  77. package/dist/providers/anthropic.js +581 -0
  78. package/dist/providers/anthropic.js.map +1 -0
  79. package/dist/providers/gemini.d.ts +42 -0
  80. package/dist/providers/gemini.d.ts.map +1 -0
  81. package/dist/providers/gemini.js +650 -0
  82. package/dist/providers/gemini.js.map +1 -0
  83. package/dist/providers/openai.d.ts +67 -0
  84. package/dist/providers/openai.d.ts.map +1 -0
  85. package/dist/providers/openai.js +1007 -0
  86. package/dist/providers/openai.js.map +1 -0
  87. package/dist/types.d.ts +461 -0
  88. package/dist/types.d.ts.map +1 -0
  89. package/dist/types.js +2 -0
  90. package/dist/types.js.map +1 -0
  91. package/dist/utils.d.ts +25 -0
  92. package/dist/utils.d.ts.map +1 -0
  93. package/dist/utils.js +331 -0
  94. package/dist/utils.js.map +1 -0
  95. package/docs/frameworks/google-adk.md +84 -0
  96. package/docs/frameworks/langchain.md +102 -0
  97. package/docs/frameworks/langgraph.md +137 -0
  98. package/docs/frameworks/llamaindex.md +82 -0
  99. package/docs/frameworks/openai-agents.md +88 -0
  100. package/docs/frameworks/vercel-ai-sdk.md +124 -0
  101. package/docs/index.md +22 -0
  102. package/docs/providers/anthropic.md +69 -0
  103. package/docs/providers/gemini.md +86 -0
  104. package/docs/providers/openai.md +151 -0
  105. package/package.json +80 -0
  106. package/proto/opentelemetry/proto/collector/trace/v1/trace_service.proto +77 -0
  107. package/proto/opentelemetry/proto/common/v1/common.proto +115 -0
  108. package/proto/opentelemetry/proto/resource/v1/resource.proto +44 -0
  109. package/proto/opentelemetry/proto/trace/v1/trace.proto +357 -0
  110. package/proto/sigil/v1/generation_ingest.proto +145 -0
@@ -0,0 +1,82 @@
1
+ # LlamaIndex Handler (`@grafana/sigil-sdk-js/llamaindex`)
2
+
3
+ Use `SigilLlamaIndexHandler` to map LlamaIndex workflow/agent callback lifecycles to Sigil generations.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @grafana/sigil-sdk-js llamaindex
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { SigilClient } from '@grafana/sigil-sdk-js';
15
+ import { withSigilLlamaIndexCallbacks } from '@grafana/sigil-sdk-js/llamaindex';
16
+ import { CallbackManager, Settings } from 'llamaindex';
17
+
18
+ const client = new SigilClient();
19
+ const callbackManager = new CallbackManager();
20
+ const config = withSigilLlamaIndexCallbacks({ callbackManager }, client, {
21
+ providerResolver: 'auto',
22
+ agentName: 'llamaindex-app',
23
+ });
24
+
25
+ Settings.callbackManager = config.callbackManager;
26
+ ```
27
+
28
+ `withSigilLlamaIndexCallbacks(...)` registers Sigil listeners through LlamaIndex's callback-manager API and returns the configured `callbackManager`.
29
+ If you already own a manager instance, use `attachSigilLlamaIndexCallbacks(existingManager, client, options)`.
30
+
31
+ ## Streaming snippet
32
+
33
+ ```ts
34
+ import { SigilClient } from '@grafana/sigil-sdk-js';
35
+ import { SigilLlamaIndexHandler } from '@grafana/sigil-sdk-js/llamaindex';
36
+
37
+ const client = new SigilClient();
38
+ const handler = new SigilLlamaIndexHandler(client, { providerResolver: 'auto' });
39
+
40
+ await handler.handleLLMStart(
41
+ { kwargs: { model: 'claude-sonnet-4-5' } },
42
+ ['stream workflow update'],
43
+ 'run-1',
44
+ undefined,
45
+ { invocation_params: { model: 'claude-sonnet-4-5', streaming: true, session_id: 'workflow-42' } }
46
+ );
47
+ await handler.handleLLMNewToken('partial ', undefined, 'run-1');
48
+ await handler.handleLLMNewToken('answer', undefined, 'run-1');
49
+ await handler.handleLLMEnd({ llm_output: { model_name: 'claude-sonnet-4-5' } }, 'run-1');
50
+ ```
51
+
52
+ ## Conversation mapping
53
+
54
+ Conversation ID precedence:
55
+
56
+ 1. `conversation_id` / `session_id` / `group_id`
57
+ 2. `thread_id`
58
+ 3. fallback: `sigil:framework:llamaindex:<run_id>`
59
+
60
+ ## Metadata and lineage
61
+
62
+ - `sigil.framework.run_type` is always set.
63
+ - Lineage keys are set when present: `run_id`, `thread_id`, `parent_run_id`, `component_name`, `retry_attempt`, `event_id`.
64
+
65
+ Required tags:
66
+
67
+ - `sigil.framework.name=llamaindex`
68
+ - `sigil.framework.source=handler`
69
+ - `sigil.framework.language=javascript`
70
+
71
+ ## Provider resolver
72
+
73
+ - `gpt-`/`o1`/`o3`/`o4` -> `openai`
74
+ - `claude-` -> `anthropic`
75
+ - `gemini-` -> `gemini`
76
+ - otherwise `custom`
77
+
78
+ ## Troubleshooting
79
+
80
+ - If lineage metadata is missing, include it in callback metadata payload.
81
+ - Keep `captureInputs` and `captureOutputs` enabled for full generation reconstruction.
82
+ - Call `await client.flush()` at checkpoints in long-running workers.
@@ -0,0 +1,88 @@
1
+ # OpenAI Agents Handler (`@grafana/sigil-sdk-js/openai-agents`)
2
+
3
+ Use `SigilOpenAIAgentsHandler` to map OpenAI Agents lifecycle callbacks to Sigil generations.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @grafana/sigil-sdk-js @openai/agents
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { SigilClient } from '@grafana/sigil-sdk-js';
15
+ import { withSigilOpenAIAgentsHooks } from '@grafana/sigil-sdk-js/openai-agents';
16
+ import { Runner } from '@openai/agents';
17
+
18
+ const client = new SigilClient();
19
+ const runner = new Runner();
20
+ const sigilHooks = withSigilOpenAIAgentsHooks(runner, client, {
21
+ providerResolver: 'auto',
22
+ agentName: 'openai-agents-app',
23
+ agentVersion: '1.0.0',
24
+ });
25
+
26
+ // optional cleanup if the runner lifecycle ends
27
+ sigilHooks.detach();
28
+ ```
29
+
30
+ `withSigilOpenAIAgentsHooks(...)` attaches Sigil listeners directly to OpenAI Agents `RunHooks`/`AgentHooks` emitters (`Runner` or `Agent`).
31
+
32
+ ## Streaming snippet
33
+
34
+ ```ts
35
+ import { SigilClient } from '@grafana/sigil-sdk-js';
36
+ import { SigilOpenAIAgentsHandler } from '@grafana/sigil-sdk-js/openai-agents';
37
+
38
+ const client = new SigilClient();
39
+ const handler = new SigilOpenAIAgentsHandler(client, { providerResolver: 'auto' });
40
+
41
+ await handler.handleLLMStart(
42
+ { kwargs: { model: 'gpt-5' } },
43
+ ['stream status'],
44
+ 'run-1',
45
+ undefined,
46
+ { invocation_params: { model: 'gpt-5', stream: true, session_id: 'session-42' } }
47
+ );
48
+ await handler.handleLLMNewToken('hello ', undefined, 'run-1');
49
+ await handler.handleLLMNewToken('world', undefined, 'run-1');
50
+ await handler.handleLLMEnd({ llm_output: { model_name: 'gpt-5' } }, 'run-1');
51
+ ```
52
+
53
+ ## Conversation mapping
54
+
55
+ Conversation ID precedence:
56
+
57
+ 1. `conversation_id` / `session_id` / `group_id` from callback metadata or invocation payload
58
+ 2. framework thread id (`thread_id`)
59
+ 3. deterministic fallback: `sigil:framework:openai-agents:<run_id>`
60
+
61
+ ## Metadata and lineage
62
+
63
+ Injected metadata keys:
64
+
65
+ - `sigil.framework.run_type` (required)
66
+ - `sigil.framework.run_id`
67
+ - `sigil.framework.thread_id`
68
+ - `sigil.framework.parent_run_id`
69
+ - `sigil.framework.component_name`
70
+ - `sigil.framework.retry_attempt`
71
+ - `sigil.framework.event_id`
72
+
73
+ Required framework tags:
74
+
75
+ - `sigil.framework.name=openai-agents`
76
+ - `sigil.framework.source=handler`
77
+ - `sigil.framework.language=javascript`
78
+
79
+ ## Provider resolver
80
+
81
+ Order: explicit provider option -> framework payload provider -> model prefix inference -> `custom`.
82
+
83
+ ## Troubleshooting
84
+
85
+ - No events exported: ensure you passed a `Runner`/`Agent` instance (not run options) to `withSigilOpenAIAgentsHooks`.
86
+ - Missing conversation grouping: pass `conversation_id` or `session_id` in callback metadata/config.
87
+ - Unknown provider: set `provider` explicitly in handler options.
88
+ - No flush at shutdown: call `await client.shutdown()`.
@@ -0,0 +1,124 @@
1
+ # Vercel AI SDK Hooks (`@grafana/sigil-sdk-js/vercel-ai-sdk`)
2
+
3
+ Use `createSigilVercelAiSdk(...)` to instrument Vercel AI SDK v5 calls with Sigil generation export, spans, metrics, tool execution spans, and streaming TTFT.
4
+
5
+ Supported AI SDK line:
6
+
7
+ - `ai` v5 (`generateText`, `streamText`)
8
+ - Baseline generation export uses `onStepFinish` (and `onError` for streams). This path is v5-compatible and records tool executions from step `toolResults`.
9
+ - When `experimental_onStepStart`, `experimental_onToolCallStart`, and `experimental_onToolCallFinish` are available (v6+), Sigil also captures richer per-step input messages and tool timing correlation.
10
+ - Experimental callbacks can change in patch releases. Keep `ai` pinned to a tested minor line (`v5.x` or `v6.x`) in production.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add @grafana/sigil-sdk-js ai
16
+ ```
17
+
18
+ ## Quickstart
19
+
20
+ ```ts
21
+ import { SigilClient } from '@grafana/sigil-sdk-js';
22
+ import { createSigilVercelAiSdk } from '@grafana/sigil-sdk-js/vercel-ai-sdk';
23
+ import { generateText } from 'ai';
24
+ import { openai } from '@ai-sdk/openai';
25
+
26
+ const client = new SigilClient();
27
+ const sigil = createSigilVercelAiSdk(client, {
28
+ agentName: 'research-agent',
29
+ agentVersion: '1.0.0',
30
+ });
31
+
32
+ const result = await generateText({
33
+ model: openai('gpt-5'),
34
+ prompt: 'Summarize this ticket in one paragraph.',
35
+ ...sigil.generateTextHooks({ conversationId: 'chat-123' }),
36
+ });
37
+ ```
38
+
39
+ The model object stays untouched. Sigil only consumes hook callbacks.
40
+
41
+ ## Conversation ID (required for multi-turn continuity)
42
+
43
+ Vercel AI SDK is stateless on the server side. For multi-turn grouping, pass a stable `conversationId` per call:
44
+
45
+ ```ts
46
+ const hooks = sigil.generateTextHooks({ conversationId: 'customer-42' });
47
+ ```
48
+
49
+ Precedence:
50
+
51
+ 1. `generateTextHooks({ conversationId })` / `streamTextHooks({ conversationId })`
52
+ 2. `resolveConversationId(stepStartEvent)` from global integration options
53
+ 3. fallback `sigil:framework:vercel-ai-sdk:<response.id>` (single-response scope)
54
+
55
+ ## Multi-step agentic loop (`generateText`)
56
+
57
+ ```ts
58
+ import { generateText, stopWhen } from 'ai';
59
+
60
+ const result = await generateText({
61
+ model: openai('gpt-5'),
62
+ prompt: 'What is the weather in Paris?',
63
+ tools: {
64
+ weather: {
65
+ description: 'Read weather by city',
66
+ inputSchema: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] },
67
+ execute: async ({ city }) => ({ city, temp_c: 18 }),
68
+ },
69
+ },
70
+ stopWhen: stopWhen.stepCountIs(2),
71
+ ...sigil.generateTextHooks({ conversationId: 'weather-chat-1' }),
72
+ });
73
+ ```
74
+
75
+ Each model step emits one generation with:
76
+
77
+ - `metadata["sigil.framework.step_type"]` (`initial`, `continue`, `tool-result`)
78
+ - per-step input captured when `experimental_onStepStart` is available (including prior tool result messages)
79
+
80
+ ## Streaming (`streamText`) and TTFT
81
+
82
+ ```ts
83
+ import { streamText } from 'ai';
84
+ import { anthropic } from '@ai-sdk/anthropic';
85
+
86
+ const stream = streamText({
87
+ model: anthropic('claude-sonnet-4-5'),
88
+ prompt: 'Stream a concise status update.',
89
+ ...sigil.streamTextHooks({ conversationId: 'stream-chat-1' }),
90
+ });
91
+
92
+ for await (const _chunk of stream.textStream) {
93
+ // consume stream
94
+ }
95
+ ```
96
+
97
+ `streamTextHooks()` records TTFT from the first text chunk (`onChunk` with `chunk.type === "text"`).
98
+
99
+ ## Privacy controls
100
+
101
+ Disable model/tool payload capture:
102
+
103
+ ```ts
104
+ const sigil = createSigilVercelAiSdk(client, {
105
+ captureInputs: false,
106
+ captureOutputs: false,
107
+ });
108
+ ```
109
+
110
+ - `captureInputs=false`: no generation input messages and no tool arguments
111
+ - `captureOutputs=false`: no generation output text and no tool results
112
+
113
+ ## Troubleshooting
114
+
115
+ - Missing usage numbers:
116
+ - Provider may not return usage fields in AI SDK `onStepFinish`.
117
+ - Sigil handles missing usage safely and exports zeros only when usage payloads exist.
118
+ - Missing TTFT:
119
+ - TTFT is only emitted for `streamText` steps where text chunks are observed.
120
+ - Tool span not appearing:
121
+ - Ensure tool has `execute` and AI SDK emits tool lifecycle callbacks.
122
+ - `toolCallId` must be present in callback payloads.
123
+ - Stream errors not exported:
124
+ - Make sure `onError` is reachable in your stream-consumption path.
package/docs/index.md ADDED
@@ -0,0 +1,22 @@
1
+ # Sigil JS SDK Docs
2
+
3
+ This directory contains public SDK usage docs for the TypeScript/JavaScript package.
4
+
5
+ ## Start Here
6
+
7
+ - SDK overview and core API: `../README.md`
8
+
9
+ ## Provider Guides
10
+
11
+ - `providers/openai.md`
12
+ - `providers/anthropic.md`
13
+ - `providers/gemini.md`
14
+
15
+ ## Framework Guides
16
+
17
+ - `frameworks/langchain.md`
18
+ - `frameworks/langgraph.md`
19
+ - `frameworks/openai-agents.md`
20
+ - `frameworks/llamaindex.md`
21
+ - `frameworks/google-adk.md`
22
+ - `frameworks/vercel-ai-sdk.md`
@@ -0,0 +1,69 @@
1
+ # Sigil JS Provider Helper: Anthropic
2
+
3
+ This helper maps strict Anthropic Messages payloads into Sigil `Generation` records.
4
+
5
+ ## Embeddings support
6
+
7
+ This helper currently supports Anthropic Messages APIs only. Native Anthropic embeddings endpoints are not available in the official SDK/API surface used in this repository.
8
+
9
+ ## Scope
10
+
11
+ - Wrapper calls:
12
+ - `anthropic.messages.create(client, request, providerCall, options?)`
13
+ - `anthropic.messages.stream(client, request, providerCall, options?)`
14
+ - Mapper functions:
15
+ - `anthropic.messages.fromRequestResponse(request, response, options?)`
16
+ - `anthropic.messages.fromStream(request, summary, options?)`
17
+ - Raw artifacts (debug opt-in):
18
+ - `request`
19
+ - `response` (sync)
20
+ - `provider_event` (stream)
21
+
22
+ ## Wrapper-first example
23
+
24
+ ```ts
25
+ import { SigilClient, anthropic } from "@grafana/sigil-sdk-js";
26
+
27
+ const client = new SigilClient();
28
+
29
+ const response = await anthropic.messages.create(
30
+ client,
31
+ {
32
+ model: "claude-sonnet-4-5",
33
+ max_tokens: 256,
34
+ messages: [{ role: "user", content: [{ type: "text", text: "Hello" }] }],
35
+ },
36
+ async (request) => provider.messages.create(request)
37
+ );
38
+ ```
39
+
40
+ ## Explicit flow example
41
+
42
+ ```ts
43
+ const recorder = client.startGeneration({
44
+ model: { provider: "anthropic", name: "claude-sonnet-4-5" },
45
+ });
46
+
47
+ try {
48
+ const response = await provider.messages.create(request);
49
+ recorder.setResult(anthropic.messages.fromRequestResponse(request, response));
50
+ } catch (error) {
51
+ recorder.setCallError(error);
52
+ throw error;
53
+ } finally {
54
+ recorder.end();
55
+ }
56
+ ```
57
+
58
+ ## Raw artifact policy
59
+
60
+ - Default OFF.
61
+ - Enable only for debug workflows with `{ rawArtifacts: true }`.
62
+
63
+ ## Provider metadata mapping
64
+
65
+ In addition to normalized usage fields, Anthropic server-tool counters are mapped into Sigil metadata when present:
66
+
67
+ - `sigil.gen_ai.usage.server_tool_use.web_search_requests`
68
+ - `sigil.gen_ai.usage.server_tool_use.web_fetch_requests`
69
+ - `sigil.gen_ai.usage.server_tool_use.total_requests`
@@ -0,0 +1,86 @@
1
+ # Sigil JS Provider Helper: Gemini
2
+
3
+ This helper maps strict Gemini `model/contents/config` payloads into Sigil `Generation` records.
4
+
5
+ ## Scope
6
+
7
+ - Wrapper calls:
8
+ - `gemini.models.generateContent(client, model, contents, config, providerCall, options?)`
9
+ - `gemini.models.generateContentStream(client, model, contents, config, providerCall, options?)`
10
+ - `gemini.models.embedContent(client, model, contents, config, providerCall, options?)`
11
+ - Mapper functions:
12
+ - `gemini.models.fromRequestResponse(model, contents, config, response, options?)`
13
+ - `gemini.models.fromStream(model, contents, config, summary, options?)`
14
+ - `gemini.models.embeddingFromResponse(model, contents, config, response)`
15
+ - Raw artifacts (debug opt-in):
16
+ - `request`
17
+ - `response` (sync)
18
+ - `provider_event` (stream)
19
+
20
+ ## Wrapper-first example
21
+
22
+ ```ts
23
+ import { SigilClient, gemini } from "@grafana/sigil-sdk-js";
24
+
25
+ const client = new SigilClient();
26
+
27
+ const model = "gemini-2.5-pro";
28
+ const contents = [{ role: "user", parts: [{ text: "Hello" }] }];
29
+ const config = { maxOutputTokens: 256 };
30
+
31
+ const response = await gemini.models.generateContent(
32
+ client,
33
+ model,
34
+ contents,
35
+ config,
36
+ async (reqModel, reqContents, reqConfig) =>
37
+ provider.models.generateContent({ model: reqModel, contents: reqContents, config: reqConfig })
38
+ );
39
+ ```
40
+
41
+ ## Explicit flow example
42
+
43
+ ```ts
44
+ const recorder = client.startGeneration({
45
+ model: { provider: "gemini", name: model },
46
+ });
47
+
48
+ try {
49
+ const response = await provider.models.generateContent({ model, contents, config });
50
+ recorder.setResult(gemini.models.fromRequestResponse(model, contents, config, response));
51
+ } catch (error) {
52
+ recorder.setCallError(error);
53
+ throw error;
54
+ } finally {
55
+ recorder.end();
56
+ }
57
+ ```
58
+
59
+ ## Embedding example
60
+
61
+ ```ts
62
+ const embeddingResponse = await gemini.models.embedContent(
63
+ client,
64
+ 'gemini-embedding-001',
65
+ [{ parts: [{ text: 'hello' }] }, { parts: [{ text: 'world' }] }],
66
+ { outputDimensionality: 256 },
67
+ async (reqModel, reqContents, reqConfig) =>
68
+ provider.models.embedContent({ model: reqModel, contents: reqContents, config: reqConfig })
69
+ );
70
+
71
+ console.log(embeddingResponse.embeddings?.length ?? 0);
72
+ ```
73
+
74
+ ## Raw artifact policy
75
+
76
+ - Default OFF.
77
+ - Enable only for debug workflows with `{ rawArtifacts: true }`.
78
+
79
+ ## Provider metadata mapping
80
+
81
+ Gemini-specific fields are mapped as follows:
82
+
83
+ - `usage.thoughtsTokenCount` -> normalized `usage.reasoningTokens`
84
+ - `usage.toolUsePromptTokenCount` -> metadata `sigil.gen_ai.usage.tool_use_prompt_tokens`
85
+ - `config.thinkingConfig.thinkingBudget` -> metadata `sigil.gen_ai.request.thinking.budget_tokens`
86
+ - `config.thinkingConfig.thinkingLevel` -> metadata `sigil.gen_ai.request.thinking.level`
@@ -0,0 +1,151 @@
1
+ # Sigil JS Provider Helper: OpenAI
2
+
3
+ This helper now mirrors official OpenAI SDK shapes for both Chat Completions and Responses.
4
+
5
+ ## Public API
6
+
7
+ - Chat Completions wrappers:
8
+ - `openai.chat.completions.create(client, request, providerCall, options?)`
9
+ - `openai.chat.completions.stream(client, request, providerCall, options?)`
10
+ - Chat Completions mappers:
11
+ - `openai.chat.completions.fromRequestResponse(request, response, options?)`
12
+ - `openai.chat.completions.fromStream(request, summary, options?)`
13
+
14
+ - Responses wrappers:
15
+ - `openai.responses.create(client, request, providerCall, options?)`
16
+ - `openai.responses.stream(client, request, providerCall, options?)`
17
+ - Responses mappers:
18
+ - `openai.responses.fromRequestResponse(request, response, options?)`
19
+ - `openai.responses.fromStream(request, summary, options?)`
20
+
21
+ - Embeddings wrapper:
22
+ - `openai.embeddings.create(client, request, providerCall, options?)`
23
+ - Embeddings mapper:
24
+ - `openai.embeddings.fromRequestResponse(request, response)`
25
+
26
+ ## Integration styles
27
+
28
+ - Strict wrappers: call OpenAI and record in one step.
29
+ - Manual instrumentation: call OpenAI yourself, then map strict OpenAI request/response payloads with `fromRequestResponse` or `fromStream`.
30
+
31
+ ## Responses-first wrapper example
32
+
33
+ ```ts
34
+ import OpenAI from 'openai';
35
+ import { SigilClient, openai } from '@grafana/sigil-sdk-js';
36
+
37
+ const sigil = new SigilClient();
38
+ const provider = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
39
+
40
+ const response = await openai.responses.create(
41
+ sigil,
42
+ {
43
+ model: 'gpt-5',
44
+ instructions: 'Be concise',
45
+ input: 'Summarize rollout status in 3 bullets',
46
+ max_output_tokens: 300,
47
+ },
48
+ async (request) => provider.responses.create(request)
49
+ );
50
+
51
+ console.log(response.output_text);
52
+ ```
53
+
54
+ ## Chat Completions stream example
55
+
56
+ ```ts
57
+ const summary = await openai.chat.completions.stream(
58
+ sigil,
59
+ {
60
+ model: 'gpt-5',
61
+ stream: true,
62
+ messages: [{ role: 'user', content: 'Stream a short status update' }],
63
+ },
64
+ async (request) => {
65
+ const stream = await provider.chat.completions.create(request);
66
+ const events = [];
67
+ for await (const event of stream) {
68
+ events.push(event);
69
+ }
70
+ return { events };
71
+ }
72
+ );
73
+ ```
74
+
75
+ ## Manual instrumentation example (strict mapper)
76
+
77
+ ```ts
78
+ const request = {
79
+ model: 'gpt-5',
80
+ instructions: 'Be concise',
81
+ input: 'Summarize rollout status in 3 bullets',
82
+ };
83
+
84
+ const options = {
85
+ conversationId: 'conv-1',
86
+ agentName: 'assistant',
87
+ agentVersion: '1.0.0',
88
+ };
89
+
90
+ const recorder = sigil.startGeneration({
91
+ conversationId: options.conversationId,
92
+ agentName: options.agentName,
93
+ agentVersion: options.agentVersion,
94
+ model: { provider: 'openai', name: request.model },
95
+ });
96
+
97
+ try {
98
+ const response = await provider.responses.create(request);
99
+ recorder.setResult(openai.responses.fromRequestResponse(request, response, options));
100
+ } catch (error) {
101
+ recorder.setCallError(error);
102
+ throw error;
103
+ } finally {
104
+ recorder.end();
105
+ }
106
+ ```
107
+
108
+ ## Embeddings example
109
+
110
+ ```ts
111
+ const embeddingResponse = await openai.embeddings.create(
112
+ sigil,
113
+ {
114
+ model: 'text-embedding-3-small',
115
+ input: ['hello', 'world'],
116
+ },
117
+ async (request) => provider.embeddings.create(request)
118
+ );
119
+
120
+ console.log(embeddingResponse.model);
121
+ ```
122
+
123
+ ## Raw artifact policy
124
+
125
+ Raw artifacts are OFF by default.
126
+
127
+ - Chat artifact names:
128
+ - `openai.chat.request`
129
+ - `openai.chat.response`
130
+ - `openai.chat.tools`
131
+ - `openai.chat.stream_events`
132
+ - Responses artifact names:
133
+ - `openai.responses.request`
134
+ - `openai.responses.response`
135
+ - `openai.responses.tools`
136
+ - `openai.responses.stream_events`
137
+
138
+ Enable only for debugging:
139
+
140
+ ```ts
141
+ { rawArtifacts: true }
142
+ ```
143
+
144
+ ## Usage mapping notes
145
+
146
+ OpenAI usage details map into normalized token usage fields:
147
+
148
+ - Chat Completions: `prompt_tokens_details.cached_tokens` -> `usage.cacheReadInputTokens`
149
+ - Chat Completions: `completion_tokens_details.reasoning_tokens` -> `usage.reasoningTokens`
150
+ - Responses: `input_tokens_details.cached_tokens` -> `usage.cacheReadInputTokens`
151
+ - Responses: `output_tokens_details.reasoning_tokens` -> `usage.reasoningTokens`