Skip to content

Commit 46bb366

Browse files
committed
wip
1 parent 73fe585 commit 46bb366

File tree

4 files changed

+75
-60
lines changed

4 files changed

+75
-60
lines changed

core/src/main/kotlin/com/simiacryptus/skyenet/core/actors/LargeOutputActor.kt

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ class LargeOutputActor(
4040
model: TextModel = OpenAIModels.GPT4o,
4141
temperature: Double = 0.3,
4242
private val maxIterations: Int = 5,
43-
private val ellipsisPattern: Regex = Regex("\\.\\.\\."),
44-
private val namedEllipsisPattern: Regex = Regex("""\.\.\.(?<sectionName>[\w\s]+)\.\.\.""")
43+
private val namedEllipsisPattern: Regex = Regex("""\.\.\.(?<sectionName>[\w\s-]+?)\.\.\.""")
4544
) : BaseActor<List<String>, String>(
4645
prompt = prompt,
4746
name = name,
@@ -67,33 +66,69 @@ class LargeOutputActor(
6766
var accumulatedResponse = ""
6867
var currentMessages = messages.toList()
6968
var iterations = 0
69+
var previousContext = ""
70+
var processedSections = mutableSetOf<String>()
7071

7172
while (iterations < maxIterations) {
7273
val response = response(*currentMessages.toTypedArray(), api = api).choices.first().message?.content
7374
?: throw RuntimeException("No response from LLM")
7475

75-
accumulatedResponse += response.trim()
76+
// Replace the ellipsis in the accumulated response with the new content
77+
if (previousContext.isNotEmpty()) {
78+
val lastEllipsis = namedEllipsisPattern.find(accumulatedResponse)
79+
if (lastEllipsis != null) {
80+
accumulatedResponse = accumulatedResponse.replaceRange(
81+
lastEllipsis.range.first,
82+
lastEllipsis.range.last + 1,
83+
response.trim()
84+
)
85+
}
86+
} else {
87+
accumulatedResponse = response.trim()
88+
}
89+
90+
val matches = namedEllipsisPattern.findAll(response)
91+
.mapNotNull { it.groups["sectionName"]?.value }
92+
.filter { it !in processedSections }
93+
.toList()
7694

77-
val matches = namedEllipsisPattern.findAll(response).mapNotNull { it.groups["sectionName"]?.value }.toList()
7895
if (matches.isNotEmpty()) {
96+
val nextSection = matches.first()
97+
processedSections.add(nextSection)
98+
7999
// Identify the pattern after the ellipsis to continue
80-
val continuationRequests = matches.map { name ->
81-
"Continue the section '$name' by expanding the ellipsis."
82-
}
83-
currentMessages = continuationRequests.map { request ->
100+
val continuationRequest = """
101+
|Previous context:
102+
|$accumulatedResponse
103+
|
104+
|Continue the section '$nextSection' by expanding the ellipsis.
105+
|Make sure the response flows naturally with the existing content.
106+
|Keep the response focused and avoid creating new ellipsis markers.
107+
""".trimMargin()
108+
currentMessages = listOf(
84109
ApiModel.ChatMessage(
85110
role = ApiModel.Role.user,
86-
content = request.toContentList()
111+
content = continuationRequest.toContentList()
87112
)
88-
}
113+
)
114+
previousContext = accumulatedResponse
89115
iterations++
90116
} else {
91117
break
92118
}
93119
}
94120

95121
if (iterations == maxIterations && namedEllipsisPattern.containsMatchIn(accumulatedResponse)) {
96-
throw RuntimeException("Maximum iterations reached. Output may be incomplete.")
122+
throw RuntimeException("""
123+
|Maximum iterations ($maxIterations) reached. Output may be incomplete.
124+
|Processed sections: ${processedSections.joinToString(", ")}
125+
|Remaining ellipsis markers: ${
126+
namedEllipsisPattern.findAll(accumulatedResponse)
127+
.mapNotNull { it.groups["sectionName"]?.value }
128+
.joinToString(", ")
129+
}
130+
|Current length: ${accumulatedResponse.length}
131+
""".trimMargin())
97132
}
98133

99134
return accumulatedResponse
@@ -106,7 +141,7 @@ class LargeOutputActor(
106141
model = model,
107142
temperature = this.temperature,
108143
maxIterations = this.maxIterations,
109-
ellipsisPattern = this.ellipsisPattern
144+
namedEllipsisPattern = this.namedEllipsisPattern
110145
)
111146
}
112147
}

webapp/src/App.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,19 @@ const AppContent: React.FC = () => {
7272
console.log('Starting component render');
7373
const appConfig = useSelector((state: RootState) => state.config);
7474
const dispatch = useDispatch();
75+
// Only load archived messages once on mount
76+
const [archivedMessagesLoaded, setArchivedMessagesLoaded] = React.useState(false);
77+
7578
// Load archived messages on mount if in archive mode
7679
React.useEffect(() => {
77-
if (isArchive) {
80+
if (isArchive && !archivedMessagesLoaded) {
7881
const archivedMessages = getArchivedMessages();
7982
if (archivedMessages) {
8083
archivedMessages.forEach((msg: Message) => dispatch(addMessage(msg)));
84+
setArchivedMessagesLoaded(true);
8185
}
8286
}
83-
}, [dispatch]);
87+
}, [dispatch, archivedMessagesLoaded]);
8488

8589
const sessionId = websocket.getSessionId();
8690
const isConnected = websocket.isConnected();

webapp/src/index.html

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,6 @@
33
<head>
44
<meta charset="utf-8"/>
55
<meta content="width=device-width, initial-scale=1" name="viewport"/>
6-
<!-- Add data-archive attribute when saving as archive -->
7-
<script>
8-
if (document.documentElement.hasAttribute('data-archive')) {
9-
// Serialize messages to a hidden element
10-
const messages = JSON.stringify(window.__MESSAGES__ || []);
11-
const messagesEl = document.createElement('script');
12-
messagesEl.id = 'archived-messages';
13-
messagesEl.type = 'application/json';
14-
messagesEl.textContent = messages;
15-
document.head.appendChild(messagesEl);
16-
}
17-
</script>
186
</head>
197
<body>
208
<div id="root"></div>

webapp/src/index.js

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import ReactDOM from 'react-dom/client';
33
import './index.css';
44
import App from './App';
55
import reportWebVitals from './reportWebVitals';
6-
// Check if we're loading from an archive
7-
const isArchive = document.documentElement.hasAttribute('data-archive');
86

97
// Application initialization timestamp
108
const startTime = performance.now();
@@ -15,57 +13,47 @@ const logStyles = {
1513
warning: 'color: #ff9800; font-weight: bold',
1614
info: 'color: #2196f3; font-weight: bold'
1715
};
16+
17+
18+
19+
// Check if we're loading from an archive based on current document length
20+
const isArchive = document.documentElement.outerHTML.length > 60000;
21+
1822
if (!isArchive) {
1923
console.log('%c[Chat App] Starting application...', logStyles.startup);
24+
} else {
25+
console.log('%c[Chat App] Starting application in archive mode...', logStyles.startup);
2026
}
2127

2228

2329
if (typeof document !== 'undefined') {
2430
if (!isArchive) {
2531
console.log('%c[Chat App] Initializing React root element...', logStyles.info);
26-
}
27-
const root = ReactDOM.createRoot(document.getElementById('root'));
28-
try {
29-
root.render(
30-
<React.StrictMode>
31-
<App isArchive={isArchive}/>
32-
</React.StrictMode>
33-
);
34-
if (!isArchive) {
32+
const root = ReactDOM.createRoot(document.getElementById('root'));
33+
try {
34+
root.render(
35+
<React.StrictMode>
36+
<App isArchive={isArchive}/>
37+
</React.StrictMode>
38+
);
3539
const renderTime = (performance.now() - startTime).toFixed(2);
3640
console.log(
3741
'%c[Chat App] Application rendered successfully in %cms',
3842
logStyles.startup,
3943
renderTime
4044
);
45+
} catch (error) {
46+
console.log(
47+
'%c[Chat App] Failed to render application:',
48+
logStyles.error,
49+
'\nError:', error,
50+
'\nStack:', error.stack
51+
);
4152
}
42-
} catch (error) {
43-
console.log(
44-
'%c[Chat App] Failed to render application:',
45-
logStyles.error,
46-
'\nError:', error,
47-
'\nStack:', error.stack
48-
);
4953
}
5054
} else {
5155
console.log(
5256
'%c[Chat App] Document is undefined - application may be running in a non-browser environment',
5357
logStyles.warning
5458
);
5559
}
56-
57-
// If you want to start measuring performance in your app, pass a function
58-
// to log results (for example: reportWebVitals(console.log))
59-
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
60-
reportWebVitals((metric) => {
61-
const metricColor = metric.rating === 'good' ? logStyles.startup :
62-
metric.rating === 'needs-improvement' ? logStyles.warning :
63-
logStyles.error;
64-
console.log(
65-
`%c[Web Vital] ${metric.name}:`,
66-
metricColor,
67-
`\nValue: ${metric.value.toFixed(2)}`,
68-
`\nRating: ${metric.rating}`,
69-
`\nDelta: ${metric.delta?.toFixed(2) || 'N/A'}`
70-
);
71-
});

0 commit comments

Comments
 (0)