Skip to content

Commit f47fe57

Browse files
committed
Simulation Environment
1 parent 77eb755 commit f47fe57

File tree

39 files changed

+955
-529
lines changed

39 files changed

+955
-529
lines changed

apps/gateway/src/services/cloudwatchMetrics.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ class CloudWatchMetricsService {
2424
}
2525

2626
private isConfigured(): boolean {
27-
return Boolean(env.AWS_ACCESS_KEY && env.AWS_ACCESS_SECRET)
27+
return Boolean(
28+
env.NODE_ENV === 'production' &&
29+
env.AWS_ACCESS_KEY &&
30+
env.AWS_ACCESS_SECRET,
31+
)
2832
}
2933

3034
incrementInflightRequests(): void {

apps/web/src/components/ChatWrapper/Message/Content/ToolCall/LatitudeTools/Code.tsx

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,56 @@ import {
1111
ToolCardWrapper,
1212
} from '../_components/ToolCard'
1313
import { ToolCardHeader } from '../_components/ToolCard/Header'
14-
import { ToolCardContentWrapper } from '../_components/ToolCard/Content'
15-
import { Alert } from '@latitude-data/web-ui/atoms/Alert'
14+
import {
15+
ToolCardContentWrapper,
16+
ToolCardOutput,
17+
} from '../_components/ToolCard/Content'
1618
import { Icon } from '@latitude-data/web-ui/atoms/Icons'
1719
import { Text } from '@latitude-data/web-ui/atoms/Text'
1820

21+
const isExpectedOutput = (toolResponse: ToolContent | undefined) => {
22+
// Returns false if the tool response does not contain the expected output
23+
if (!toolResponse) return false
24+
if (toolResponse.isError) return false
25+
26+
if (typeof toolResponse.result !== 'string') return false
27+
return true
28+
}
29+
30+
function RunCodeOutput({
31+
toolResponse,
32+
simulated,
33+
}: {
34+
toolResponse: ToolContent | undefined
35+
simulated?: boolean
36+
}) {
37+
const isExpectedResponse = useMemo(
38+
() => isExpectedOutput(toolResponse),
39+
[toolResponse],
40+
)
41+
42+
if (!toolResponse) {
43+
return (
44+
<ToolCardContentWrapper>
45+
<div className='flex flex-row gap-2 items-center justify-center pb-3'>
46+
<Icon name='loader' color='foregroundMuted' spin />
47+
<Text.H5 color='foregroundMuted'>Running code...</Text.H5>
48+
</div>
49+
</ToolCardContentWrapper>
50+
)
51+
}
52+
53+
if (!isExpectedResponse) {
54+
return <ToolCardOutput toolResponse={toolResponse} simulated={simulated} />
55+
}
56+
57+
return (
58+
<ToolCardContentWrapper>
59+
<CodeBlock language='shell'>{toolResponse.result as string}</CodeBlock>
60+
</ToolCardContentWrapper>
61+
)
62+
}
63+
1964
function runCodeContent(args: CodeToolArgs): string {
2065
if (!args.dependencies) return args.code
2166

@@ -49,34 +94,17 @@ export function RunCodeLatitudeToolCard({
4994
status={status}
5095
isOpen={isOpen}
5196
onToggle={() => setIsOpen(!isOpen)}
97+
simulated={toolRequest._sourceData?.simulated}
5298
/>
5399
{isOpen && (
54100
<>
55101
<ToolCardContentWrapper>
56102
<CodeBlock language={args.language}>{value}</CodeBlock>
57103
</ToolCardContentWrapper>
58-
<ToolCardContentWrapper badge='Output'>
59-
{toolResponse ? (
60-
toolResponse.isError ? (
61-
<div className='w-full pt-3 items-center'>
62-
<Alert
63-
variant='destructive'
64-
title='Error'
65-
description={JSON.stringify(toolResponse.result, null, 2)}
66-
/>
67-
</div>
68-
) : (
69-
<CodeBlock language='shell'>
70-
{toolResponse.result as string}
71-
</CodeBlock>
72-
)
73-
) : (
74-
<div className='flex flex-row gap-2 items-center justify-center pb-3'>
75-
<Icon name='loader' color='foregroundMuted' spin />
76-
<Text.H5 color='foregroundMuted'>Running code...</Text.H5>
77-
</div>
78-
)}
79-
</ToolCardContentWrapper>
104+
<RunCodeOutput
105+
toolResponse={toolResponse}
106+
simulated={toolRequest._sourceData?.simulated}
107+
/>
80108
</>
81109
)}
82110
</ToolCardWrapper>

apps/web/src/components/ChatWrapper/Message/Content/ToolCall/LatitudeTools/Extract.tsx

Lines changed: 70 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,73 @@ import {
1616
ToolCardWrapper,
1717
} from '../_components/ToolCard'
1818
import { ToolCardHeader } from '../_components/ToolCard/Header'
19-
import { ToolCardContentWrapper } from '../_components/ToolCard/Content'
20-
import { Alert } from '@latitude-data/web-ui/atoms/Alert'
19+
import {
20+
ToolCardContentWrapper,
21+
ToolCardOutput,
22+
} from '../_components/ToolCard/Content'
2123
import { Icon } from '@latitude-data/web-ui/atoms/Icons'
2224

25+
const isExpectedOutput = (toolResponse: ToolContent | undefined) => {
26+
// Returns false if the tool response does not contain the expected output
27+
if (!toolResponse) return false
28+
if (toolResponse.isError) return false
29+
30+
if (typeof toolResponse.result !== 'object' || toolResponse.result === null) {
31+
return false
32+
}
33+
34+
if (!('content' in toolResponse.result)) return false
35+
const { content } = toolResponse.result
36+
if (typeof content !== 'string') return false
37+
38+
return true
39+
}
40+
41+
function WebExtractOutput({
42+
toolResponse,
43+
simulated,
44+
}: {
45+
toolResponse: ToolContent | undefined
46+
simulated?: boolean
47+
}) {
48+
const isExpectedResponse = useMemo(
49+
() => isExpectedOutput(toolResponse),
50+
[toolResponse],
51+
)
52+
53+
const markdownContent = useMemo(() => {
54+
if (!isExpectedResponse) return undefined
55+
return (toolResponse!.result as ExtractToolResult).content
56+
}, [toolResponse, isExpectedResponse])
57+
58+
if (!toolResponse) {
59+
return (
60+
<ToolCardContentWrapper>
61+
<div className='flex flex-row gap-2 items-center justify-center pb-3'>
62+
<Icon name='loader' color='foregroundMuted' spin />
63+
<Text.H5 color='foregroundMuted'>Loading page...</Text.H5>
64+
</div>
65+
</ToolCardContentWrapper>
66+
)
67+
}
68+
69+
if (!isExpectedResponse) {
70+
return <ToolCardOutput toolResponse={toolResponse} simulated={simulated} />
71+
}
72+
73+
return (
74+
<ToolCardContentWrapper>
75+
{markdownContent ? (
76+
<Markdown size='sm' color='foregroundMuted'>
77+
{markdownContent}
78+
</Markdown>
79+
) : (
80+
<Text.H5 color='foregroundMuted'>No content</Text.H5>
81+
)}
82+
</ToolCardContentWrapper>
83+
)
84+
}
85+
2386
export function WebExtractLatitudeToolCard({
2487
toolRequest,
2588
toolResponse,
@@ -30,12 +93,6 @@ export function WebExtractLatitudeToolCard({
3093
status: 'pending' | 'success' | 'error'
3194
}) {
3295
const [isOpen, setIsOpen] = useState(false)
33-
34-
const markdownContent = useMemo(() => {
35-
if (!toolResponse || toolResponse.isError) return undefined
36-
return (toolResponse.result as ExtractToolResult).content
37-
}, [toolResponse])
38-
3996
const args = toolRequest.args as ExtractToolArgs
4097

4198
return (
@@ -46,36 +103,13 @@ export function WebExtractLatitudeToolCard({
46103
status={status}
47104
isOpen={isOpen}
48105
onToggle={() => setIsOpen(!isOpen)}
106+
simulated={toolRequest._sourceData?.simulated}
49107
/>
50108
{isOpen && (
51-
<ToolCardContentWrapper>
52-
{toolResponse ? (
53-
toolResponse.isError ? (
54-
<div className='w-full pt-3 items-center'>
55-
<Alert
56-
variant='destructive'
57-
title='Error'
58-
description={JSON.stringify(toolResponse.result, null, 2)}
59-
/>
60-
</div>
61-
) : (
62-
<div className='flex flex-col gap-4'>
63-
{markdownContent ? (
64-
<Markdown size='sm' color='primary'>
65-
{markdownContent}
66-
</Markdown>
67-
) : (
68-
<Text.H5 color='foregroundMuted'>No content</Text.H5>
69-
)}
70-
</div>
71-
)
72-
) : (
73-
<div className='flex flex-row gap-2 items-center justify-center pb-3'>
74-
<Icon name='loader' color='foregroundMuted' spin />
75-
<Text.H5 color='foregroundMuted'>Loading page...</Text.H5>
76-
</div>
77-
)}
78-
</ToolCardContentWrapper>
109+
<WebExtractOutput
110+
toolResponse={toolResponse}
111+
simulated={toolRequest._sourceData?.simulated}
112+
/>
79113
)}
80114
</ToolCardWrapper>
81115
)

apps/web/src/components/ChatWrapper/Message/Content/ToolCall/LatitudeTools/Search.tsx

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import {
1616
ToolCardWrapper,
1717
} from '../_components/ToolCard'
1818
import { ToolCardHeader } from '../_components/ToolCard/Header'
19-
import { ToolCardContentWrapper } from '../_components/ToolCard/Content'
20-
import { Alert } from '@latitude-data/web-ui/atoms/Alert'
19+
import {
20+
ToolCardContentWrapper,
21+
ToolCardOutput,
22+
} from '../_components/ToolCard/Content'
2123

2224
function topicText({
2325
topic,
@@ -93,6 +95,87 @@ function WebSearchResult({
9395
)
9496
}
9597

98+
const isExpectedOutput = (toolResponse: ToolContent | undefined) => {
99+
// Returns false if the tool response does not contain the expected output
100+
if (!toolResponse) return false
101+
if (toolResponse.isError) return false
102+
103+
if (typeof toolResponse.result !== 'object' || toolResponse.result === null) {
104+
return false
105+
}
106+
107+
if (!('results' in toolResponse.result)) return false
108+
const results = toolResponse.result.results
109+
110+
if (!Array.isArray(results)) return false
111+
if (results.length === 0) return true
112+
113+
if (
114+
results.some(
115+
(result) =>
116+
typeof result !== 'object' ||
117+
result === null ||
118+
!('title' in result) ||
119+
typeof result.title !== 'string' ||
120+
!('url' in result) ||
121+
typeof result.url !== 'string' ||
122+
!('content' in result) ||
123+
typeof result.content !== 'string',
124+
)
125+
) {
126+
return false
127+
}
128+
129+
return true
130+
}
131+
132+
function WebSearchOutput({
133+
toolResponse,
134+
simulated,
135+
}: {
136+
toolResponse: ToolContent | undefined
137+
simulated?: boolean
138+
}) {
139+
const isExpectedResponse = useMemo(
140+
() => isExpectedOutput(toolResponse),
141+
[toolResponse],
142+
)
143+
144+
const searchResults = useMemo(() => {
145+
if (!isExpectedResponse) return []
146+
return (toolResponse!.result as SearchToolResult).results
147+
}, [toolResponse, isExpectedResponse])
148+
149+
if (!toolResponse) {
150+
return (
151+
<ToolCardContentWrapper>
152+
<div className='flex flex-row gap-2 items-center justify-center pb-3'>
153+
<Icon name='loader' color='foregroundMuted' spin />
154+
<Text.H5 color='foregroundMuted'>Searching...</Text.H5>
155+
</div>
156+
</ToolCardContentWrapper>
157+
)
158+
}
159+
160+
if (!isExpectedResponse) {
161+
return <ToolCardOutput toolResponse={toolResponse} simulated={simulated} />
162+
}
163+
164+
return (
165+
<ToolCardContentWrapper>
166+
<div className='flex flex-col gap-4'>
167+
{searchResults.length ? (
168+
searchResults.map((result, index) => (
169+
<WebSearchResult key={index} result={result} />
170+
))
171+
) : (
172+
<Text.H5 color='foregroundMuted'>No results found</Text.H5>
173+
)}
174+
</div>
175+
</ToolCardContentWrapper>
176+
)
177+
}
178+
96179
export function WebSearchLatitudeToolCard({
97180
toolRequest,
98181
toolResponse,
@@ -103,12 +186,6 @@ export function WebSearchLatitudeToolCard({
103186
status: 'pending' | 'success' | 'error'
104187
}) {
105188
const [isOpen, setIsOpen] = useState(false)
106-
107-
const searchResults = useMemo(() => {
108-
if (!toolResponse || toolResponse.isError) return []
109-
return (toolResponse.result as SearchToolResult).results
110-
}, [toolResponse])
111-
112189
const args = toolRequest.args as SearchToolArgs
113190

114191
return (
@@ -124,36 +201,13 @@ export function WebSearchLatitudeToolCard({
124201
status={status}
125202
isOpen={isOpen}
126203
onToggle={() => setIsOpen(!isOpen)}
204+
simulated={toolRequest._sourceData?.simulated}
127205
/>
128206
{isOpen && (
129-
<ToolCardContentWrapper>
130-
{toolResponse ? (
131-
toolResponse.isError ? (
132-
<div className='w-full pt-3 items-center'>
133-
<Alert
134-
variant='destructive'
135-
title='Error'
136-
description={JSON.stringify(toolResponse.result, null, 2)}
137-
/>
138-
</div>
139-
) : (
140-
<div className='flex flex-col gap-4'>
141-
{searchResults.length ? (
142-
searchResults.map((result, index) => (
143-
<WebSearchResult key={index} result={result} />
144-
))
145-
) : (
146-
<Text.H5 color='foregroundMuted'>No results found</Text.H5>
147-
)}
148-
</div>
149-
)
150-
) : (
151-
<div className='flex flex-row gap-2 items-center justify-center pb-3'>
152-
<Icon name='loader' color='foregroundMuted' spin />
153-
<Text.H5 color='foregroundMuted'>Searching...</Text.H5>
154-
</div>
155-
)}
156-
</ToolCardContentWrapper>
207+
<WebSearchOutput
208+
toolResponse={toolResponse}
209+
simulated={toolRequest._sourceData?.simulated}
210+
/>
157211
)}
158212
</ToolCardWrapper>
159213
)

0 commit comments

Comments
 (0)