fix(opencode): restore effect error logging (#31551)
This commit is contained in:
@@ -586,7 +586,13 @@ export const layer = Layer.effect(
|
|||||||
|
|
||||||
if (target.type === "remote") {
|
if (target.type === "remote") {
|
||||||
yield* syncHistory(previous, target.url, target.headers).pipe(
|
yield* syncHistory(previous, target.url, target.headers).pipe(
|
||||||
Effect.catch((error) => Effect.sync(() => {})),
|
Effect.catch((error) =>
|
||||||
|
Effect.logWarning("session warp final source sync failed", {
|
||||||
|
workspaceID: previous.id,
|
||||||
|
sessionID: input.sessionID,
|
||||||
|
error: errorData(error),
|
||||||
|
}),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
yield* prompt.cancel(input.sessionID)
|
yield* prompt.cancel(input.sessionID)
|
||||||
@@ -739,9 +745,7 @@ export const layer = Layer.effect(
|
|||||||
([type, adapter]) =>
|
([type, adapter]) =>
|
||||||
WorkspaceAdapterRuntime.list(adapter).pipe(
|
WorkspaceAdapterRuntime.list(adapter).pipe(
|
||||||
Effect.catchCause((error) =>
|
Effect.catchCause((error) =>
|
||||||
Effect.sync(() => {
|
Effect.logWarning("workspace adapter list failed", { type, error }).pipe(Effect.as([])),
|
||||||
return []
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
{ concurrency: "unbounded" },
|
{ concurrency: "unbounded" },
|
||||||
@@ -817,7 +821,7 @@ export const layer = Layer.effect(
|
|||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* WorkspaceAdapterRuntime.remove(info)
|
yield* WorkspaceAdapterRuntime.remove(info)
|
||||||
}),
|
}),
|
||||||
() => Effect.sync(() => {}),
|
() => Effect.logError("adapter not available when removing workspace", { type: row.type }),
|
||||||
)
|
)
|
||||||
|
|
||||||
yield* db.delete(WorkspaceTable).where(eq(WorkspaceTable.id, id)).run().pipe(Effect.orDie)
|
yield* db.delete(WorkspaceTable).where(eq(WorkspaceTable.id, id)).run().pipe(Effect.orDie)
|
||||||
|
|||||||
@@ -215,6 +215,12 @@ function fetchFromClient<T extends { name: string }>(
|
|||||||
return e
|
return e
|
||||||
},
|
},
|
||||||
}).pipe(
|
}).pipe(
|
||||||
|
Effect.tapError((error) =>
|
||||||
|
Effect.logWarning(`failed to get ${label}`, {
|
||||||
|
clientName,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
}),
|
||||||
|
),
|
||||||
Effect.map((items) => {
|
Effect.map((items) => {
|
||||||
const out: Record<string, T & { client: string }> = {}
|
const out: Record<string, T & { client: string }> = {}
|
||||||
const sanitizedClient = sanitize(clientName)
|
const sanitizedClient = sanitize(clientName)
|
||||||
@@ -529,6 +535,7 @@ export const layer = Layer.effect(
|
|||||||
([key, mcp]) =>
|
([key, mcp]) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
if (!isMcpConfigured(mcp)) {
|
if (!isMcpConfigured(mcp)) {
|
||||||
|
yield* Effect.logError("Ignoring MCP config entry without type", { key })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,6 +686,7 @@ export const layer = Layer.effect(
|
|||||||
|
|
||||||
const listed = s.defs[clientName]
|
const listed = s.defs[clientName]
|
||||||
if (!listed) {
|
if (!listed) {
|
||||||
|
yield* Effect.logWarning("missing cached tools for connected server", { clientName })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,6 +752,7 @@ export const layer = Layer.effect(
|
|||||||
const s = yield* InstanceState.get(state)
|
const s = yield* InstanceState.get(state)
|
||||||
const client = s.clients[clientName]
|
const client = s.clients[clientName]
|
||||||
if (!client) {
|
if (!client) {
|
||||||
|
yield* Effect.logWarning(`client not found for ${label}`, { clientName })
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return yield* Effect.tryPromise({
|
return yield* Effect.tryPromise({
|
||||||
@@ -751,7 +760,16 @@ export const layer = Layer.effect(
|
|||||||
catch: (e: any) => {
|
catch: (e: any) => {
|
||||||
return e
|
return e
|
||||||
},
|
},
|
||||||
}).pipe(Effect.orElseSucceed(() => undefined))
|
}).pipe(
|
||||||
|
Effect.tapError((error) =>
|
||||||
|
Effect.logError(`failed to ${label}`, {
|
||||||
|
clientName,
|
||||||
|
...meta,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Effect.orElseSucceed(() => undefined),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const getPrompt = Effect.fn("MCP.getPrompt")(function* (
|
const getPrompt = Effect.fn("MCP.getPrompt")(function* (
|
||||||
|
|||||||
@@ -162,8 +162,13 @@ export const layer = Layer.effect(
|
|||||||
for (const plugin of flags.disableDefaultPlugins ? [] : internalPlugins(flags)) {
|
for (const plugin of flags.disableDefaultPlugins ? [] : internalPlugins(flags)) {
|
||||||
const init = yield* Effect.tryPromise({
|
const init = yield* Effect.tryPromise({
|
||||||
try: () => plugin(input),
|
try: () => plugin(input),
|
||||||
catch: (err) => {},
|
catch: errorMessage,
|
||||||
}).pipe(Effect.option)
|
}).pipe(
|
||||||
|
Effect.tapError((error) =>
|
||||||
|
Effect.logError("failed to load internal plugin", { name: plugin.name, error }),
|
||||||
|
),
|
||||||
|
Effect.option,
|
||||||
|
)
|
||||||
if (init._tag === "Some") hooks.push(init.value)
|
if (init._tag === "Some") hooks.push(init.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +222,7 @@ export const layer = Layer.effect(
|
|||||||
return message
|
return message
|
||||||
},
|
},
|
||||||
}).pipe(
|
}).pipe(
|
||||||
|
Effect.tapError((error) => Effect.logError("failed to load plugin", { path: load.spec, error })),
|
||||||
Effect.catch(() => {
|
Effect.catch(() => {
|
||||||
// TODO: make proper events for this
|
// TODO: make proper events for this
|
||||||
// events.publish(Session.Event.Error, {
|
// events.publish(Session.Event.Error, {
|
||||||
@@ -256,8 +262,11 @@ export const layer = Layer.effect(
|
|||||||
(hook) =>
|
(hook) =>
|
||||||
Effect.tryPromise({
|
Effect.tryPromise({
|
||||||
try: () => Promise.resolve(hook.dispose?.()),
|
try: () => Promise.resolve(hook.dispose?.()),
|
||||||
catch: (error) => {},
|
catch: errorMessage,
|
||||||
}).pipe(Effect.ignore),
|
}).pipe(
|
||||||
|
Effect.tapError((error) => Effect.logError("plugin dispose hook failed", { error })),
|
||||||
|
Effect.ignore,
|
||||||
|
),
|
||||||
{ discard: true },
|
{ discard: true },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ const live: Layer.Layer<
|
|||||||
// Wire up toolExecutor for DWS workflow models so that tool calls
|
// Wire up toolExecutor for DWS workflow models so that tool calls
|
||||||
// from the workflow service are executed via opencode's tool system
|
// from the workflow service are executed via opencode's tool system
|
||||||
// and results sent back over the WebSocket.
|
// and results sent back over the WebSocket.
|
||||||
|
const bridge = yield* EffectBridge.make()
|
||||||
if (language instanceof GitLabWorkflowLanguageModel) {
|
if (language instanceof GitLabWorkflowLanguageModel) {
|
||||||
const workflowModel = language as GitLabWorkflowLanguageModel & {
|
const workflowModel = language as GitLabWorkflowLanguageModel & {
|
||||||
sessionID?: string
|
sessionID?: string
|
||||||
@@ -149,7 +150,6 @@ const live: Layer.Layer<
|
|||||||
return !match || match.action !== "ask"
|
return !match || match.action !== "ask"
|
||||||
})
|
})
|
||||||
|
|
||||||
const bridge = yield* EffectBridge.make()
|
|
||||||
const approvedToolsForSession = new Set<string>()
|
const approvedToolsForSession = new Set<string>()
|
||||||
workflowModel.approvalHandler = bridge.bind(async (approvalTools) => {
|
workflowModel.approvalHandler = bridge.bind(async (approvalTools) => {
|
||||||
const uniqueNames = [...new Set(approvalTools.map((t: { name: string }) => t.name))] as string[]
|
const uniqueNames = [...new Set(approvalTools.map((t: { name: string }) => t.name))] as string[]
|
||||||
@@ -276,6 +276,19 @@ const live: Layer.Layer<
|
|||||||
return {
|
return {
|
||||||
type: "ai-sdk" as const,
|
type: "ai-sdk" as const,
|
||||||
result: streamText({
|
result: streamText({
|
||||||
|
onError(error) {
|
||||||
|
bridge.fork(
|
||||||
|
Effect.logError("stream error", {
|
||||||
|
providerID: input.model.providerID,
|
||||||
|
modelID: input.model.id,
|
||||||
|
"session.id": input.sessionID,
|
||||||
|
small: (input.small ?? false).toString(),
|
||||||
|
agent: input.agent.name,
|
||||||
|
mode: input.agent.mode,
|
||||||
|
error,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
},
|
||||||
// Copilot returns the authoritative billed amount only in provider-specific response fields.
|
// Copilot returns the authoritative billed amount only in provider-specific response fields.
|
||||||
includeRawChunks: input.model.providerID.includes("github-copilot"),
|
includeRawChunks: input.model.providerID.includes("github-copilot"),
|
||||||
async experimental_repairToolCall(failed) {
|
async experimental_repairToolCall(failed) {
|
||||||
|
|||||||
Reference in New Issue
Block a user