• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacklok / toolhive-studio / 29571051485

17 Jul 2026 09:44AM UTC coverage: 71.713% (+0.5%) from 71.204%
29571051485

Pull #2475

github

samuv
fix(chat): harden Effect runtime adapters after external review

Make readiness and runtime retrieval atomic, type adapter programs against
ChatServices, and tighten domain-error narrowing plus agent/settings edge cases.

Co-authored-by: Cursor <cursoragent@cursor.com>
Pull Request #2475: refactor(chat): migrate main-process chat to Effect domain services

5476 of 8187 branches covered (66.89%)

871 of 1363 new or added lines in 42 files covered. (63.9%)

1 existing line in 1 file now uncovered.

8153 of 11369 relevant lines covered (71.71%)

137.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.13
/main/src/chat/runtime/adapters.ts
1
import { Cause, Effect, Exit } from 'effect'
2
import {
3
  CHAT_UNAVAILABLE_USER_MESSAGE,
4
  ChatUnavailableError,
5
  type ChatDomainError,
6
  getDomainUserMessage,
7
} from './errors'
8
import type { ChatServices } from './managed-runtime'
9
import { getManagedRuntime } from './runtime-ref'
10

11
type ResultSuccess<T> = { success: true } & T
12
export type ResultFailure = { success: false; error: string }
13
export type OperationResult<
14
  T extends Record<string, unknown> = Record<string, unknown>,
15
> = ResultSuccess<T> | ResultFailure
16

17
const DOMAIN_ERROR_TAGS = new Set<ChatDomainError['_tag']>([
12✔
18
  'ChatUnavailableError',
19
  'StorageError',
20
  'ThreadNotFoundError',
21
  'ThreadAlreadyExistsError',
22
  'ProviderError',
23
  'McpDiscoveryError',
24
  'McpServerUnavailableError',
25
  'StreamConflictError',
26
  'ValidationError',
27
])
28

29
export function unavailableResult(
30
  error = CHAT_UNAVAILABLE_USER_MESSAGE
1✔
31
): ResultFailure {
32
  return { success: false, error }
1✔
33
}
34

35
function unavailableError(): ChatUnavailableError {
36
  return new ChatUnavailableError({
1✔
37
    reason: 'runtime_not_ready',
38
    userMessage: CHAT_UNAVAILABLE_USER_MESSAGE,
39
  })
40
}
41

42
export function runChatPromise<A, E>(
43
  program: Effect.Effect<A, E, ChatServices>
44
): Promise<A> {
45
  const runtime = getManagedRuntime()
49✔
46
  if (!runtime) {
49!
NEW
47
    return Promise.reject(toThrownError(unavailableError()))
×
48
  }
49
  return runtime.runPromiseExit(program).then(throwFromExit)
49✔
50
}
51

52
export function runChatSync<A, E>(
53
  program: Effect.Effect<A, E, ChatServices>
54
): A {
55
  const runtime = getManagedRuntime()
78✔
56
  if (!runtime) {
78✔
57
    throw toThrownError(unavailableError())
1✔
58
  }
59
  return throwFromExit(runtime.runSyncExit(program))
77✔
60
}
61

62
/** Like `runChatSync`, but returns `fallback` when the runtime is unavailable. */
63
export function runChatSyncOr<A, E>(
64
  program: Effect.Effect<A, E, ChatServices>,
65
  fallback: A
66
): A {
67
  const runtime = getManagedRuntime()
8✔
68
  if (!runtime) return fallback
8✔
69
  return throwFromExit(runtime.runSyncExit(program))
7✔
70
}
71

72
/** Like `runChatPromise`, but resolves to `fallback` when the runtime is unavailable. */
73
export function runChatPromiseOr<A, E>(
74
  program: Effect.Effect<A, E, ChatServices>,
75
  fallback: A
76
): Promise<A> {
77
  const runtime = getManagedRuntime()
1✔
78
  if (!runtime) return Promise.resolve(fallback)
1!
NEW
79
  return runtime.runPromiseExit(program).then(throwFromExit)
×
80
}
81

82
function runChatPromiseExit<A, E>(
83
  program: Effect.Effect<A, E, ChatServices>
84
): Promise<Exit.Exit<A, E>> {
85
  const runtime = getManagedRuntime()
18✔
86
  if (!runtime) {
18!
NEW
87
    return Promise.resolve(Exit.fail(unavailableError() as E))
×
88
  }
89
  return runtime.runPromiseExit(program)
18✔
90
}
91

92
export async function runChatToResult<A extends Record<string, unknown>, E>(
93
  program: Effect.Effect<A, E, ChatServices>
94
): Promise<OperationResult<A>> {
95
  const exit = await runChatPromiseExit(program)
18✔
96
  if (Exit.isSuccess(exit)) {
18✔
97
    return { success: true, ...exit.value }
10✔
98
  }
99

100
  const failure = Cause.failureOption(exit.cause)
8✔
101
  if (failure._tag === 'Some' && isDomainError(failure.value)) {
8!
102
    return { success: false, error: getDomainUserMessage(failure.value) }
8✔
103
  }
104

NEW
105
  return {
×
106
    success: false,
107
    error: Cause.pretty(exit.cause) || 'Unknown error',
×
108
  }
109
}
110

111
export function runChatToResultSync<A extends Record<string, unknown>, E>(
112
  program: Effect.Effect<A, E, ChatServices>
113
): OperationResult<A> {
114
  const runtime = getManagedRuntime()
22✔
115
  if (!runtime) {
22!
NEW
116
    return unavailableResult()
×
117
  }
118

119
  const exit = runtime.runSyncExit(program)
22✔
120
  if (Exit.isSuccess(exit)) {
22✔
121
    return { success: true, ...exit.value }
16✔
122
  }
123

124
  const failure = Cause.failureOption(exit.cause)
6✔
125
  if (failure._tag === 'Some' && isDomainError(failure.value)) {
6!
126
    return { success: false, error: getDomainUserMessage(failure.value) }
6✔
127
  }
128

NEW
129
  return {
×
130
    success: false,
131
    error: Cause.pretty(exit.cause) || 'Unknown error',
×
132
  }
133
}
134

135
function isDomainError(error: unknown): error is ChatDomainError {
136
  return (
29✔
137
    typeof error === 'object' &&
203✔
138
    error !== null &&
139
    '_tag' in error &&
140
    typeof (error as { _tag: unknown })._tag === 'string' &&
141
    DOMAIN_ERROR_TAGS.has((error as { _tag: ChatDomainError['_tag'] })._tag) &&
142
    'userMessage' in error &&
143
    typeof (error as { userMessage: unknown }).userMessage === 'string'
144
  )
145
}
146

147
function toThrownError(error: ChatDomainError | Error): Error {
148
  if (isDomainError(error)) {
8!
149
    const thrown = new Error(getDomainUserMessage(error))
8✔
150
    thrown.cause = error
8✔
151
    return thrown
8✔
152
  }
NEW
153
  return error
×
154
}
155

156
function throwFromExit<A, E>(exit: Exit.Exit<A, E>): A {
157
  if (Exit.isSuccess(exit)) {
130✔
158
    return exit.value
123✔
159
  }
160

161
  const failure = Cause.failureOption(exit.cause)
7✔
162
  if (failure._tag === 'Some') {
7!
163
    if (isDomainError(failure.value)) {
7!
164
      throw toThrownError(failure.value)
7✔
165
    }
NEW
166
    if (failure.value instanceof Error) {
×
NEW
167
      throw failure.value
×
168
    }
169
  }
170

NEW
171
  throw new Error(Cause.pretty(exit.cause) || 'Unknown error')
×
172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc