mirror of
https://github.com/anomalyco/opencode.git
synced 2026-04-15 18:34:48 +00:00
Compare commits
3 Commits
dev
...
fix/otel-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9de336fa44 | ||
|
|
bba33ba84f | ||
|
|
3b9d14b83b |
2
bun.lock
2
bun.lock
@@ -359,6 +359,8 @@
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/server": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "2.5.1",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/context-async-hooks": "2.6.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
|
||||
"@opentelemetry/sdk-trace-base": "2.6.1",
|
||||
"@opentelemetry/sdk-trace-node": "2.6.1",
|
||||
|
||||
@@ -113,13 +113,15 @@
|
||||
"@octokit/rest": "catalog:",
|
||||
"@openauthjs/openauth": "catalog:",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/server": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/server": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "2.5.1",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/context-async-hooks": "2.6.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
|
||||
"@opentelemetry/sdk-trace-base": "2.6.1",
|
||||
"@opentelemetry/sdk-trace-node": "2.6.1",
|
||||
"@openrouter/ai-sdk-provider": "2.5.1",
|
||||
"@opentui/core": "0.1.99",
|
||||
"@opentui/solid": "0.1.99",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
|
||||
@@ -46,6 +46,18 @@ export namespace Observability {
|
||||
const OTLP = await import("@opentelemetry/exporter-trace-otlp-http")
|
||||
const SdkBase = await import("@opentelemetry/sdk-trace-base")
|
||||
|
||||
// @effect/opentelemetry creates a NodeTracerProvider but never calls
|
||||
// register(), so the global @opentelemetry/api context manager stays
|
||||
// as the no-op default. Non-Effect code (like the AI SDK) that calls
|
||||
// tracer.startActiveSpan() relies on context.active() to find the
|
||||
// parent span — without a real context manager every span starts a
|
||||
// new trace. Registering AsyncLocalStorageContextManager fixes this.
|
||||
const { AsyncLocalStorageContextManager } = await import("@opentelemetry/context-async-hooks")
|
||||
const { context } = await import("@opentelemetry/api")
|
||||
const mgr = new AsyncLocalStorageContextManager()
|
||||
mgr.enable()
|
||||
context.setGlobalContextManager(mgr)
|
||||
|
||||
return NodeSdk.layer(() => ({
|
||||
resource,
|
||||
spanProcessor: new SdkBase.BatchSpanProcessor(
|
||||
|
||||
@@ -5,12 +5,10 @@ import { Config } from "../../config/config"
|
||||
import { Provider } from "../../provider/provider"
|
||||
import { mapValues } from "remeda"
|
||||
import { errors } from "../error"
|
||||
import { Log } from "../../util/log"
|
||||
import { lazy } from "../../util/lazy"
|
||||
import { AppRuntime } from "../../effect/app-runtime"
|
||||
import { Effect } from "effect"
|
||||
|
||||
const log = Log.create({ service: "server" })
|
||||
import { jsonRequest } from "./trace"
|
||||
|
||||
export const ConfigRoutes = lazy(() =>
|
||||
new Hono()
|
||||
@@ -31,9 +29,11 @@ export const ConfigRoutes = lazy(() =>
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
return c.json(await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.get())))
|
||||
},
|
||||
async (c) =>
|
||||
jsonRequest("ConfigRoutes.get", c, function* () {
|
||||
const cfg = yield* Config.Service
|
||||
return yield* cfg.get()
|
||||
}),
|
||||
)
|
||||
.patch(
|
||||
"/",
|
||||
@@ -82,18 +82,14 @@ export const ConfigRoutes = lazy(() =>
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
using _ = log.time("providers")
|
||||
const providers = await AppRuntime.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Provider.Service
|
||||
return mapValues(yield* svc.list(), (item) => item)
|
||||
}),
|
||||
)
|
||||
return c.json({
|
||||
providers: Object.values(providers),
|
||||
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
|
||||
})
|
||||
},
|
||||
async (c) =>
|
||||
jsonRequest("ConfigRoutes.providers", c, function* () {
|
||||
const svc = yield* Provider.Service
|
||||
const providers = mapValues(yield* svc.list(), (item) => item)
|
||||
return {
|
||||
providers: Object.values(providers),
|
||||
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ import { errors } from "../error"
|
||||
import { lazy } from "../../util/lazy"
|
||||
import { Bus } from "../../bus"
|
||||
import { NamedError } from "@opencode-ai/shared/util/error"
|
||||
import { jsonRequest } from "./trace"
|
||||
|
||||
const log = Log.create({ service: "server" })
|
||||
|
||||
@@ -94,10 +95,11 @@ export const SessionRoutes = lazy(() =>
|
||||
...errors(400),
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const result = await AppRuntime.runPromise(SessionStatus.Service.use((svc) => svc.list()))
|
||||
return c.json(Object.fromEntries(result))
|
||||
},
|
||||
async (c) =>
|
||||
jsonRequest("SessionRoutes.status", c, function* () {
|
||||
const svc = yield* SessionStatus.Service
|
||||
return Object.fromEntries(yield* svc.list())
|
||||
}),
|
||||
)
|
||||
.get(
|
||||
"/:sessionID",
|
||||
@@ -126,8 +128,10 @@ export const SessionRoutes = lazy(() =>
|
||||
),
|
||||
async (c) => {
|
||||
const sessionID = c.req.valid("param").sessionID
|
||||
const session = await AppRuntime.runPromise(Session.Service.use((svc) => svc.get(sessionID)))
|
||||
return c.json(session)
|
||||
return jsonRequest("SessionRoutes.get", c, function* () {
|
||||
const session = yield* Session.Service
|
||||
return yield* session.get(sessionID)
|
||||
})
|
||||
},
|
||||
)
|
||||
.get(
|
||||
@@ -157,8 +161,10 @@ export const SessionRoutes = lazy(() =>
|
||||
),
|
||||
async (c) => {
|
||||
const sessionID = c.req.valid("param").sessionID
|
||||
const session = await AppRuntime.runPromise(Session.Service.use((svc) => svc.children(sessionID)))
|
||||
return c.json(session)
|
||||
return jsonRequest("SessionRoutes.children", c, function* () {
|
||||
const session = yield* Session.Service
|
||||
return yield* session.children(sessionID)
|
||||
})
|
||||
},
|
||||
)
|
||||
.get(
|
||||
@@ -187,8 +193,10 @@ export const SessionRoutes = lazy(() =>
|
||||
),
|
||||
async (c) => {
|
||||
const sessionID = c.req.valid("param").sessionID
|
||||
const todos = await AppRuntime.runPromise(Todo.Service.use((svc) => svc.get(sessionID)))
|
||||
return c.json(todos)
|
||||
return jsonRequest("SessionRoutes.todo", c, function* () {
|
||||
const todo = yield* Todo.Service
|
||||
return yield* todo.get(sessionID)
|
||||
})
|
||||
},
|
||||
)
|
||||
.post(
|
||||
|
||||
31
packages/opencode/src/server/instance/trace.ts
Normal file
31
packages/opencode/src/server/instance/trace.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { Context } from "hono"
|
||||
import { Effect } from "effect"
|
||||
import { AppRuntime } from "../../effect/app-runtime"
|
||||
|
||||
export function runRequest<A, E>(name: string, c: Context, effect: Effect.Effect<A, E, any>) {
|
||||
const url = new URL(c.req.url)
|
||||
return AppRuntime.runPromise(
|
||||
effect.pipe(
|
||||
Effect.withSpan(name, {
|
||||
attributes: {
|
||||
"http.method": c.req.method,
|
||||
"http.path": url.pathname,
|
||||
},
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
export async function jsonRequest<C extends Context, A, E>(
|
||||
name: string,
|
||||
c: C,
|
||||
effect: (c: C) => Effect.gen.Return<A, E, any>,
|
||||
) {
|
||||
return c.json(
|
||||
await runRequest(
|
||||
name,
|
||||
c,
|
||||
Effect.gen(() => effect(c)),
|
||||
),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user