weave-codex 0.1.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 (48) hide show
  1. package/LICENSES/MIT.txt +21 -0
  2. package/README.md +144 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +149 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/collector.d.ts +19 -0
  7. package/dist/collector.js +162 -0
  8. package/dist/collector.js.map +1 -0
  9. package/dist/config.d.ts +23 -0
  10. package/dist/config.js +99 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/constants.d.ts +16 -0
  13. package/dist/constants.js +42 -0
  14. package/dist/constants.js.map +1 -0
  15. package/dist/install.d.ts +14 -0
  16. package/dist/install.js +177 -0
  17. package/dist/install.js.map +1 -0
  18. package/dist/lock.d.ts +7 -0
  19. package/dist/lock.js +67 -0
  20. package/dist/lock.js.map +1 -0
  21. package/dist/log.d.ts +4 -0
  22. package/dist/log.js +45 -0
  23. package/dist/log.js.map +1 -0
  24. package/dist/model.d.ts +58 -0
  25. package/dist/model.js +5 -0
  26. package/dist/model.js.map +1 -0
  27. package/dist/rollout/cursor.d.ts +13 -0
  28. package/dist/rollout/cursor.js +74 -0
  29. package/dist/rollout/cursor.js.map +1 -0
  30. package/dist/rollout/parser.d.ts +26 -0
  31. package/dist/rollout/parser.js +359 -0
  32. package/dist/rollout/parser.js.map +1 -0
  33. package/dist/rollout/types.d.ts +213 -0
  34. package/dist/rollout/types.js +33 -0
  35. package/dist/rollout/types.js.map +1 -0
  36. package/dist/semconv.d.ts +37 -0
  37. package/dist/semconv.js +41 -0
  38. package/dist/semconv.js.map +1 -0
  39. package/dist/spans/emit.d.ts +14 -0
  40. package/dist/spans/emit.js +143 -0
  41. package/dist/spans/emit.js.map +1 -0
  42. package/dist/spans/messages.d.ts +26 -0
  43. package/dist/spans/messages.js +38 -0
  44. package/dist/spans/messages.js.map +1 -0
  45. package/dist/spans/tracer.d.ts +20 -0
  46. package/dist/spans/tracer.js +43 -0
  47. package/dist/spans/tracer.js.map +1 -0
  48. package/package.json +48 -0
@@ -0,0 +1,41 @@
1
+ // SPDX-FileCopyrightText: 2026 CoreWeave, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-PackageName: weave-codex
4
+ /**
5
+ * The pieces the OpenTelemetry semantic-conventions package doesn't give us as a
6
+ * usable value. Standard attribute keys and gen_ai.* enum values are imported
7
+ * straight from the package where they're used (see spans/emit.ts); this file
8
+ * holds only what the package doesn't export:
9
+ * - gen_ai.tool.type values (the package exports the key, not the values)
10
+ * - our vendor keys (weave / wandb / codex / mcp)
11
+ */
12
+ /** `gen_ai.tool.type` values (the spec package exports the key, not the values). */
13
+ export const TOOL_TYPE = {
14
+ FUNCTION: 'function', // local_shell, apply_patch, MCP, user functions
15
+ EXTENSION: 'extension', // provider-executed tools (e.g. web_search)
16
+ };
17
+ /**
18
+ * MCP tool-call context. Attached to the same execute_tool span (per the spec)
19
+ * rather than a separate MCP span. Not typed by the spec package.
20
+ */
21
+ export const MCP = {
22
+ SERVER_NAME: 'mcp.server.name',
23
+ TOOL_NAME: 'mcp.tool.name',
24
+ };
25
+ /** Resource attributes — entity/project routing also goes via the project_id header. */
26
+ export const RESOURCE = {
27
+ WANDB_ENTITY: 'wandb.entity',
28
+ WANDB_PROJECT: 'wandb.project',
29
+ SDK_LANGUAGE: 'weave.sdk.language',
30
+ SDK_VERSION: 'weave.sdk.version',
31
+ };
32
+ /** Codex-specific vendor extensions (no canonical gen_ai key exists for these). */
33
+ export const CODEX = {
34
+ SESSION_ID: 'codex.session.id',
35
+ TURN_ID: 'codex.turn.id',
36
+ CLI_VERSION: 'codex.cli_version',
37
+ CWD: 'codex.cwd',
38
+ /** Stamped only once we wire up model price tables; UI sums tokens meanwhile. */
39
+ COST_USD: 'codex.usage.cost_usd',
40
+ };
41
+ //# sourceMappingURL=semconv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semconv.js","sourceRoot":"","sources":["../src/semconv.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,+BAA+B;AAC/B,gCAAgC;AAEhC;;;;;;;GAOG;AAEH,oFAAoF;AACpF,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,QAAQ,EAAE,UAAU,EAAE,gDAAgD;IACtE,SAAS,EAAE,WAAW,EAAE,4CAA4C;CAC5D,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,WAAW,EAAE,iBAAiB;IAC9B,SAAS,EAAE,eAAe;CAClB,CAAC;AAEX,wFAAwF;AACxF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAC9B,YAAY,EAAE,oBAAoB;IAClC,WAAW,EAAE,mBAAmB;CACxB,CAAC;AAEX,mFAAmF;AACnF,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,eAAe;IACxB,WAAW,EAAE,mBAAmB;IAChC,GAAG,EAAE,WAAW;IAChB,iFAAiF;IACjF,QAAQ,EAAE,sBAAsB;CACxB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Turn a ReconstructedTurn into a backdated OTEL span tree:
3
+ *
4
+ * invoke_agent codex (root; start/end = turn bounds)
5
+ * ├─ chat <model> (one per model call; per-call usage + output)
6
+ * └─ execute_tool <name> (one per tool; arguments + result)
7
+ *
8
+ * chat and execute_tool are siblings under the turn (the GenAI-spec convention).
9
+ * Every span carries gen_ai.conversation.id so Weave stitches turns server-side.
10
+ * Start/end times come from the rollout, which is the whole point of the shim.
11
+ */
12
+ import { type Tracer } from '@opentelemetry/api';
13
+ import type { ReconstructedTurn } from '../model.js';
14
+ export declare function emitTurn(tracer: Tracer, turn: ReconstructedTurn, captureContent: boolean): void;
@@ -0,0 +1,143 @@
1
+ // SPDX-FileCopyrightText: 2026 CoreWeave, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-PackageName: weave-codex
4
+ /**
5
+ * Turn a ReconstructedTurn into a backdated OTEL span tree:
6
+ *
7
+ * invoke_agent codex (root; start/end = turn bounds)
8
+ * ├─ chat <model> (one per model call; per-call usage + output)
9
+ * └─ execute_tool <name> (one per tool; arguments + result)
10
+ *
11
+ * chat and execute_tool are siblings under the turn (the GenAI-spec convention).
12
+ * Every span carries gen_ai.conversation.id so Weave stitches turns server-side.
13
+ * Start/end times come from the rollout, which is the whole point of the shim.
14
+ */
15
+ import { context, SpanKind, SpanStatusCode, trace, } from '@opentelemetry/api';
16
+ import { ATTR_ERROR_TYPE, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, } from '@opentelemetry/semantic-conventions';
17
+ import { ATTR_GEN_AI_AGENT_NAME, ATTR_GEN_AI_AGENT_VERSION, ATTR_GEN_AI_CONVERSATION_ID, ATTR_GEN_AI_INPUT_MESSAGES, ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_OUTPUT_MESSAGES, ATTR_GEN_AI_PROVIDER_NAME, ATTR_GEN_AI_REQUEST_MODEL, ATTR_GEN_AI_REQUEST_STREAM, ATTR_GEN_AI_RESPONSE_FINISH_REASONS, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_TOOL_CALL_ARGUMENTS, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_CALL_RESULT, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_TOOL_TYPE, ATTR_GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, ATTR_GEN_AI_USAGE_INPUT_TOKENS, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, GEN_AI_OPERATION_NAME_VALUE_CHAT, GEN_AI_OPERATION_NAME_VALUE_EXECUTE_TOOL, GEN_AI_OPERATION_NAME_VALUE_INVOKE_AGENT, GEN_AI_PROVIDER_NAME_VALUE_OPENAI, } from '@opentelemetry/semantic-conventions/incubating';
18
+ import { CODEX, MCP, TOOL_TYPE } from '../semconv.js';
19
+ import { chatOutputMessages, finalMessages, userMessages } from './messages.js';
20
+ const AGENT_NAME = 'codex';
21
+ const OPENAI_API_HOST = 'api.openai.com';
22
+ const OPENAI_API_PORT = 443;
23
+ /** Truncate any single attribute value (tool args/results, messages) past this. */
24
+ const MAX_ATTR_VALUE_BYTES = 128 * 1024;
25
+ const TRUNCATION_MARKER = '…[truncated]';
26
+ export function emitTurn(tracer, turn, captureContent) {
27
+ const root = tracer.startSpan(`${GEN_AI_OPERATION_NAME_VALUE_INVOKE_AGENT} ${AGENT_NAME}`, {
28
+ kind: SpanKind.INTERNAL, // in-process agent (GenAI-spec span kind)
29
+ startTime: turn.startTime,
30
+ attributes: invokeAgentAttributes(turn, captureContent),
31
+ });
32
+ const parentCtx = trace.setSpan(context.active(), root);
33
+ for (const chat of turn.chats)
34
+ emitChat(tracer, parentCtx, turn, chat, captureContent);
35
+ for (const tool of turn.tools)
36
+ emitTool(tracer, parentCtx, turn, tool, captureContent);
37
+ root.end(turn.endTime);
38
+ }
39
+ function invokeAgentAttributes(turn, captureContent) {
40
+ const spanAttributes = {
41
+ [ATTR_GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_INVOKE_AGENT,
42
+ [ATTR_GEN_AI_PROVIDER_NAME]: GEN_AI_PROVIDER_NAME_VALUE_OPENAI,
43
+ [ATTR_GEN_AI_AGENT_NAME]: AGENT_NAME,
44
+ [ATTR_GEN_AI_CONVERSATION_ID]: turn.conversationId,
45
+ [ATTR_GEN_AI_REQUEST_MODEL]: turn.model,
46
+ [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: ['stop'],
47
+ [CODEX.SESSION_ID]: turn.sessionId,
48
+ [CODEX.TURN_ID]: turn.turnId,
49
+ };
50
+ if (turn.cliVersion)
51
+ spanAttributes[ATTR_GEN_AI_AGENT_VERSION] = turn.cliVersion;
52
+ if (turn.cwd)
53
+ spanAttributes[CODEX.CWD] = turn.cwd;
54
+ addUsage(spanAttributes, turn.usageTotal);
55
+ if (captureContent) {
56
+ setJson(spanAttributes, ATTR_GEN_AI_INPUT_MESSAGES, userMessages(turn));
57
+ setJson(spanAttributes, ATTR_GEN_AI_OUTPUT_MESSAGES, finalMessages(turn));
58
+ }
59
+ return spanAttributes;
60
+ }
61
+ function emitChat(tracer, parent, turn, chat, captureContent) {
62
+ const spanAttributes = {
63
+ [ATTR_GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_CHAT,
64
+ [ATTR_GEN_AI_PROVIDER_NAME]: GEN_AI_PROVIDER_NAME_VALUE_OPENAI,
65
+ [ATTR_GEN_AI_REQUEST_MODEL]: turn.model,
66
+ [ATTR_GEN_AI_RESPONSE_MODEL]: turn.model,
67
+ [ATTR_GEN_AI_CONVERSATION_ID]: turn.conversationId,
68
+ [ATTR_GEN_AI_REQUEST_STREAM]: true,
69
+ [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [chat.finishReason],
70
+ [ATTR_SERVER_ADDRESS]: OPENAI_API_HOST,
71
+ [ATTR_SERVER_PORT]: OPENAI_API_PORT,
72
+ };
73
+ if (chat.usage)
74
+ addUsage(spanAttributes, chat.usage);
75
+ if (captureContent)
76
+ setJson(spanAttributes, ATTR_GEN_AI_OUTPUT_MESSAGES, chatOutputMessages(chat));
77
+ const span = tracer.startSpan(`${GEN_AI_OPERATION_NAME_VALUE_CHAT} ${turn.model}`, {
78
+ kind: SpanKind.CLIENT, // model round-trip (GenAI-spec span kind)
79
+ startTime: clamp(chat.startTime, turn.startTime, turn.endTime),
80
+ attributes: spanAttributes,
81
+ }, parent);
82
+ span.end(clamp(chat.endTime, turn.startTime, turn.endTime));
83
+ }
84
+ function emitTool(tracer, parent, turn, tool, captureContent) {
85
+ const spanAttributes = {
86
+ [ATTR_GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_EXECUTE_TOOL,
87
+ [ATTR_GEN_AI_TOOL_NAME]: tool.name,
88
+ [ATTR_GEN_AI_TOOL_TYPE]: tool.kind === 'web_search' ? TOOL_TYPE.EXTENSION : TOOL_TYPE.FUNCTION,
89
+ [ATTR_GEN_AI_TOOL_CALL_ID]: tool.callId,
90
+ [ATTR_GEN_AI_CONVERSATION_ID]: turn.conversationId,
91
+ };
92
+ if (tool.mcpServer)
93
+ spanAttributes[MCP.SERVER_NAME] = tool.mcpServer;
94
+ if (tool.error)
95
+ spanAttributes[ATTR_ERROR_TYPE] = tool.error;
96
+ if (captureContent) {
97
+ if (tool.arguments)
98
+ spanAttributes[ATTR_GEN_AI_TOOL_CALL_ARGUMENTS] = truncate(tool.arguments);
99
+ if (tool.result != null)
100
+ spanAttributes[ATTR_GEN_AI_TOOL_CALL_RESULT] = truncate(tool.result);
101
+ }
102
+ const span = tracer.startSpan(`${GEN_AI_OPERATION_NAME_VALUE_EXECUTE_TOOL} ${tool.name}`, {
103
+ kind: SpanKind.INTERNAL, // tool execution (GenAI-spec span kind)
104
+ startTime: clamp(tool.startTime, turn.startTime, turn.endTime),
105
+ attributes: spanAttributes,
106
+ }, parent);
107
+ if (tool.error)
108
+ span.setStatus({ code: SpanStatusCode.ERROR, message: tool.error });
109
+ span.end(clamp(tool.endTime, turn.startTime, turn.endTime));
110
+ }
111
+ function addUsage(spanAttributes, usage) {
112
+ spanAttributes[ATTR_GEN_AI_USAGE_INPUT_TOKENS] = usage.inputTokens;
113
+ spanAttributes[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS] = usage.outputTokens;
114
+ if (usage.cachedInputTokens > 0) {
115
+ spanAttributes[ATTR_GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] =
116
+ usage.cachedInputTokens;
117
+ }
118
+ if (usage.reasoningOutputTokens > 0) {
119
+ spanAttributes[ATTR_GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] =
120
+ usage.reasoningOutputTokens;
121
+ }
122
+ }
123
+ function setJson(spanAttributes, key, value) {
124
+ if (Array.isArray(value) && value.length === 0)
125
+ return;
126
+ spanAttributes[key] = truncate(JSON.stringify(value));
127
+ }
128
+ function truncate(value) {
129
+ const buffer = Buffer.from(value, 'utf8');
130
+ if (buffer.byteLength <= MAX_ATTR_VALUE_BYTES)
131
+ return value;
132
+ // Cut on a byte boundary (the budget is bytes), and let a non-fatal decode drop
133
+ // a trailing split multibyte char so we never emit a lone surrogate.
134
+ const keepBytes = MAX_ATTR_VALUE_BYTES - Buffer.byteLength(TRUNCATION_MARKER, 'utf8');
135
+ const head = new TextDecoder('utf-8').decode(buffer.subarray(0, keepBytes));
136
+ return head + TRUNCATION_MARKER;
137
+ }
138
+ /** Keep a child span's timestamps within its parent's window so traces render. */
139
+ function clamp(time, windowStart, windowEnd) {
140
+ const clampedMs = Math.min(Math.max(time.getTime(), windowStart.getTime()), windowEnd.getTime());
141
+ return new Date(clampedMs);
142
+ }
143
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/spans/emit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Build `gen_ai.input.messages` / `gen_ai.output.messages` payloads.
3
+ *
4
+ * The Weave Agents extractor mines `text` and `reasoning` parts for chat content
5
+ * and renders tool cards from `execute_tool` SPANS (not from tool_call message
6
+ * parts) — so we keep messages focused on assistant content and let the tool
7
+ * spans carry arguments/results. Shapes follow the Weave SDK MessagePart union.
8
+ */
9
+ import type { ChatCall, ReconstructedTurn } from '../model.js';
10
+ interface MessagePart {
11
+ type: 'text' | 'reasoning' | 'tool_call';
12
+ content?: string;
13
+ toolCallId?: string;
14
+ toolName?: string;
15
+ arguments?: string;
16
+ }
17
+ interface ChatMessage {
18
+ role: string;
19
+ content?: string;
20
+ parts?: MessagePart[];
21
+ finish_reason?: string;
22
+ }
23
+ export declare function userMessages(turn: ReconstructedTurn): ChatMessage[];
24
+ export declare function finalMessages(turn: ReconstructedTurn): ChatMessage[];
25
+ export declare function chatOutputMessages(chat: ChatCall): ChatMessage[];
26
+ export {};
@@ -0,0 +1,38 @@
1
+ // SPDX-FileCopyrightText: 2026 CoreWeave, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-PackageName: weave-codex
4
+ export function userMessages(turn) {
5
+ if (!turn.userMessage)
6
+ return [];
7
+ return [{ role: 'user', content: turn.userMessage }];
8
+ }
9
+ export function finalMessages(turn) {
10
+ if (!turn.finalAssistantMessage)
11
+ return [];
12
+ return [
13
+ {
14
+ role: 'assistant',
15
+ content: turn.finalAssistantMessage,
16
+ finish_reason: 'stop',
17
+ },
18
+ ];
19
+ }
20
+ export function chatOutputMessages(chat) {
21
+ const parts = [];
22
+ if (chat.reasoning)
23
+ parts.push({ type: 'reasoning', content: chat.reasoning });
24
+ if (chat.text)
25
+ parts.push({ type: 'text', content: chat.text });
26
+ for (const toolCall of chat.toolCalls) {
27
+ parts.push({
28
+ type: 'tool_call',
29
+ toolCallId: toolCall.callId,
30
+ toolName: toolCall.name,
31
+ ...(toolCall.arguments ? { arguments: toolCall.arguments } : {}),
32
+ });
33
+ }
34
+ if (parts.length === 0)
35
+ return [];
36
+ return [{ role: 'assistant', parts, finish_reason: chat.finishReason }];
37
+ }
38
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/spans/messages.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,+BAA+B;AAC/B,gCAAgC;AA2BhC,MAAM,UAAU,YAAY,CAAC,IAAuB;IAClD,IAAI,CAAC,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,CAAC;IACjC,OAAO,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAC,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,IAAI,CAAC,IAAI,CAAC,qBAAqB;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO;QACL;YACE,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,IAAI,CAAC,qBAAqB;YACnC,aAAa,EAAE,MAAM;SACtB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAC/C,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,IAAI,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,EAAC,CAAC,CAAC;IAC7E,IAAI,IAAI,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAC,CAAC,CAAC;IAC9D,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,WAAW;YACjB,UAAU,EAAE,QAAQ,CAAC,MAAM;YAC3B,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,CAAC,EAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,YAAY,EAAC,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * A self-owned OpenTelemetry pipeline pointed at Weave's Agents OTLP endpoint.
3
+ * Spans are built through the raw OTel API rather than the Weave TS SDK's GenAI
4
+ * helpers because those helpers cannot set historical timestamps, and this
5
+ * collector backdates every span to when the turn actually happened. The emitter
6
+ * can move onto the SDK if it gains start/end-time parameters.
7
+ *
8
+ * Auth headers for the Agents OTLP endpoint:
9
+ * Authorization: Basic base64("api:" + WANDB_API_KEY)
10
+ * project_id: <entity>/<project>
11
+ */
12
+ import type { Tracer } from '@opentelemetry/api';
13
+ import type { ResolvedConfig } from '../config.js';
14
+ /** The OTel pipeline as one unit; injected into the collector so tests can swap in an in-memory exporter. */
15
+ export interface TracerHandle {
16
+ tracer: Tracer;
17
+ /** Flush queued spans and tear down the exporter. Always await before exit. */
18
+ shutdown: () => Promise<void>;
19
+ }
20
+ export declare function buildTracer(config: ResolvedConfig): TracerHandle;
@@ -0,0 +1,43 @@
1
+ // SPDX-FileCopyrightText: 2026 CoreWeave, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-PackageName: weave-codex
4
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
5
+ import { resourceFromAttributes } from '@opentelemetry/resources';
6
+ import { BasicTracerProvider, BatchSpanProcessor, } from '@opentelemetry/sdk-trace-base';
7
+ import { GENAI_OTLP_PATH, VERSION } from '../constants.js';
8
+ import { RESOURCE } from '../semconv.js';
9
+ const SERVICE_NAME = 'weave-codex';
10
+ export function buildTracer(config) {
11
+ const exporter = new OTLPTraceExporter({
12
+ url: `${config.baseUrl}${GENAI_OTLP_PATH}`,
13
+ headers: {
14
+ Authorization: `Basic ${Buffer.from(`api:${config.apiKey}`).toString('base64')}`,
15
+ project_id: config.projectId,
16
+ },
17
+ });
18
+ const resource = resourceFromAttributes({
19
+ 'service.name': SERVICE_NAME,
20
+ [RESOURCE.WANDB_ENTITY]: config.entity,
21
+ [RESOURCE.WANDB_PROJECT]: config.project,
22
+ [RESOURCE.SDK_LANGUAGE]: 'node',
23
+ [RESOURCE.SDK_VERSION]: VERSION,
24
+ });
25
+ const provider = new BasicTracerProvider({
26
+ resource,
27
+ spanProcessors: [new BatchSpanProcessor(exporter)],
28
+ });
29
+ return {
30
+ tracer: provider.getTracer(SERVICE_NAME, VERSION),
31
+ shutdown: async () => {
32
+ // Always tear the provider down, but let a forceFlush rejection (transport
33
+ // failure) propagate so the caller knows the spans did not land.
34
+ try {
35
+ await provider.forceFlush();
36
+ }
37
+ finally {
38
+ await provider.shutdown();
39
+ }
40
+ },
41
+ };
42
+ }
43
+ //# sourceMappingURL=tracer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracer.js","sourceRoot":"","sources":["../../src/spans/tracer.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,+BAA+B;AAC/B,gCAAgC;AAchC,OAAO,EAAC,iBAAiB,EAAC,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAC,eAAe,EAAE,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AAEvC,MAAM,YAAY,GAAG,aAAa,CAAC;AASnC,MAAM,UAAU,WAAW,CAAC,MAAsB;IAChD,MAAM,QAAQ,GAAG,IAAI,iBAAiB,CAAC;QACrC,GAAG,EAAE,GAAG,MAAM,CAAC,OAAO,GAAG,eAAe,EAAE;QAC1C,OAAO,EAAE;YACP,aAAa,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAChF,UAAU,EAAE,MAAM,CAAC,SAAS;SAC7B;KACF,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,sBAAsB,CAAC;QACtC,cAAc,EAAE,YAAY;QAC5B,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM;QACtC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,OAAO;QACxC,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM;QAC/B,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO;KAChC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,IAAI,mBAAmB,CAAC;QACvC,QAAQ;QACR,cAAc,EAAE,CAAC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;KACnD,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC;QACjD,QAAQ,EAAE,KAAK,IAAI,EAAE;YACnB,2EAA2E;YAC3E,iEAAiE;YACjE,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC9B,CAAC;oBAAS,CAAC;gBACT,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAC5B,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "weave-codex",
3
+ "version": "0.1.0",
4
+ "description": "W&B Weave observability for OpenAI Codex CLI — reconstructs gen_ai OpenTelemetry spans from Codex rollout sessions and ships them to Weave, fully off the critical path.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/wandb/codex_weave_plugin.git"
10
+ },
11
+ "bin": {
12
+ "weave-codex": "dist/cli.js"
13
+ },
14
+ "files": [
15
+ "dist/",
16
+ "LICENSES/",
17
+ "README.md"
18
+ ],
19
+ "engines": {
20
+ "node": ">=20"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc -p tsconfig.build.json && node scripts/build/postbuild.mjs",
24
+ "typecheck": "tsc -p tsconfig.json --noEmit",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "lint": "prettier --check . && tsc -p tsconfig.json --noEmit",
28
+ "format": "prettier --write .",
29
+ "secrets:scan": "gitleaks dir . --no-banner --redact",
30
+ "secrets:scan:staged": "gitleaks git --pre-commit --staged --redact --verbose",
31
+ "check": "npm run build && npm run lint && npm test && npm run secrets:scan",
32
+ "setup-hooks": "node scripts/install-git-hooks.mjs",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "dependencies": {
36
+ "@opentelemetry/api": "^1.9.1",
37
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
38
+ "@opentelemetry/resources": "^2.7.1",
39
+ "@opentelemetry/sdk-trace-base": "^2.7.1",
40
+ "@opentelemetry/semantic-conventions": "^1.41.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22",
44
+ "prettier": "^3.3",
45
+ "typescript": "^5.6",
46
+ "vitest": "^4.1.8"
47
+ }
48
+ }