osborn 0.8.14 ā 0.8.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/caresource-apply.js +50 -0
- package/caresource-apply.mjs +34 -0
- package/dist/index.js +64 -6
- package/package.json +1 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const { chromium } = require('playwright');
|
|
2
|
+
|
|
3
|
+
(async () => {
|
|
4
|
+
const browser = await chromium.launch({ headless: false });
|
|
5
|
+
const page = await browser.newPage();
|
|
6
|
+
|
|
7
|
+
await page.goto('https://caresource.wd1.myworkdayjobs.com/CareSource/job/Remote/AI-Developer_R10487/apply', { waitUntil: 'networkidle' });
|
|
8
|
+
await page.waitForTimeout(2000);
|
|
9
|
+
|
|
10
|
+
// Click Apply Manually
|
|
11
|
+
console.log('Clicking Apply Manually...');
|
|
12
|
+
await page.click('text=Apply Manually');
|
|
13
|
+
await page.waitForTimeout(3000);
|
|
14
|
+
|
|
15
|
+
// Fill in email
|
|
16
|
+
console.log('Filling email field...');
|
|
17
|
+
const emailInput = await page.$('input[type="email"]');
|
|
18
|
+
if (emailInput) {
|
|
19
|
+
await emailInput.fill('osbornojure@gmail.com');
|
|
20
|
+
console.log('Email filled: osbornojure@gmail.com');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Fill in password
|
|
24
|
+
console.log('Filling password fields...');
|
|
25
|
+
const passwordInputs = await page.$$('input[type="password"]');
|
|
26
|
+
if (passwordInputs.length >= 2) {
|
|
27
|
+
await passwordInputs[0].fill('workday2026!');
|
|
28
|
+
await passwordInputs[1].fill('workday2026!');
|
|
29
|
+
console.log('Passwords filled');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
await page.waitForTimeout(1000);
|
|
33
|
+
|
|
34
|
+
// Click Create Account
|
|
35
|
+
const createBtn = await page.$('text=Create Account');
|
|
36
|
+
if (createBtn) {
|
|
37
|
+
console.log('Clicking Create Account...');
|
|
38
|
+
await createBtn.click();
|
|
39
|
+
await page.waitForTimeout(3000);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Take screenshot
|
|
43
|
+
await page.screenshot({ path: '/tmp/caresource-step1.png' });
|
|
44
|
+
console.log('Screenshot saved to /tmp/caresource-step1.png');
|
|
45
|
+
|
|
46
|
+
// Get current page text
|
|
47
|
+
const text = await page.evaluate(() => document.body.innerText);
|
|
48
|
+
console.log('\n--- PAGE CONTENT ---');
|
|
49
|
+
console.log(text);
|
|
50
|
+
})();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { chromium } from 'playwright';
|
|
2
|
+
|
|
3
|
+
(async () => {
|
|
4
|
+
const browser = await chromium.launch({ headless: false });
|
|
5
|
+
const page = await browser.newPage();
|
|
6
|
+
|
|
7
|
+
console.log('š Navigating to CareSource...');
|
|
8
|
+
await page.goto('https://caresource.wd1.myworkdayjobs.com/CareSource/job/Remote/AI-Developer_R10487/apply', { waitUntil: 'networkidle' });
|
|
9
|
+
await page.waitForTimeout(2000);
|
|
10
|
+
|
|
11
|
+
console.log('š Clicking Apply Manually...');
|
|
12
|
+
await page.click('text=Apply Manually');
|
|
13
|
+
await page.waitForTimeout(3000);
|
|
14
|
+
|
|
15
|
+
console.log('š§ Filling email...');
|
|
16
|
+
const emailInput = await page.$('input[type="email"]');
|
|
17
|
+
if (emailInput) {
|
|
18
|
+
await emailInput.fill('osbornojure@gmail.com');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log('š Filling passwords...');
|
|
22
|
+
const passwordInputs = await page.$$('input[type="password"]');
|
|
23
|
+
if (passwordInputs.length >= 2) {
|
|
24
|
+
await passwordInputs[0].fill('workday2026!');
|
|
25
|
+
await passwordInputs[1].fill('workday2026!');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await page.waitForTimeout(1000);
|
|
29
|
+
await page.screenshot({ path: '/tmp/caresource-step1.png' });
|
|
30
|
+
|
|
31
|
+
console.log('ā
Account form filled. Screenshot saved.');
|
|
32
|
+
console.log('\nš Browser is now open. You can review before submitting.');
|
|
33
|
+
console.log('Keep this window open and ready to proceed.\n');
|
|
34
|
+
})();
|
package/dist/index.js
CHANGED
|
@@ -818,7 +818,18 @@ async function main() {
|
|
|
818
818
|
proactivePromptHistory = [];
|
|
819
819
|
}
|
|
820
820
|
// Helper to send data to frontend (with size limit handling)
|
|
821
|
-
|
|
821
|
+
//
|
|
822
|
+
// WebRTC SCTP data channel max message size is ~256KB. Sending larger
|
|
823
|
+
// payloads corrupts the publisher transport, killing ALL subsequent sends.
|
|
824
|
+
// We enforce a soft limit (truncate text/content fields) and a hard limit
|
|
825
|
+
// (drop the message entirely with a warning) to prevent this.
|
|
826
|
+
// ā ļø These limits protect the LiveKit SCTP publisher peer connection.
|
|
827
|
+
// During session resume, 12 artifact requests arrive simultaneously and the agent
|
|
828
|
+
// sends responses back-to-back. If the cumulative payload exceeds the SCTP buffer
|
|
829
|
+
// (~50-100 KB in rapid fire), the publisher PC enters a zombie state and NEVER
|
|
830
|
+
// recovers ā the user hears nothing for the rest of the connection. Keep these low.
|
|
831
|
+
const MAX_MESSAGE_SIZE = 30000; // 30KB soft limit ā truncate text/content fields
|
|
832
|
+
const HARD_MAX_MESSAGE_SIZE = 50000; // 50KB hard limit ā drop if still too large after truncation
|
|
822
833
|
async function sendToFrontend(data) {
|
|
823
834
|
if (!localParticipant) {
|
|
824
835
|
console.log('ā ļø sendToFrontend: no localParticipant!');
|
|
@@ -827,18 +838,36 @@ async function main() {
|
|
|
827
838
|
try {
|
|
828
839
|
const encoder = new TextEncoder();
|
|
829
840
|
let jsonData = JSON.stringify(data);
|
|
830
|
-
// If message is too large, truncate the text content
|
|
841
|
+
// If message is too large, truncate the text or content field
|
|
831
842
|
if (jsonData.length > MAX_MESSAGE_SIZE) {
|
|
832
843
|
const truncatedData = { ...data };
|
|
844
|
+
// Try truncating .text first (assistant_response, claude_output, etc.)
|
|
833
845
|
if (truncatedData.text && typeof truncatedData.text === 'string') {
|
|
834
846
|
const overhead = JSON.stringify({ ...truncatedData, text: '' }).length;
|
|
835
847
|
const maxTextLength = MAX_MESSAGE_SIZE - overhead - 100;
|
|
836
848
|
truncatedData.text = truncatedData.text.substring(0, maxTextLength) + '\n\n[Message truncated due to size limit]';
|
|
837
849
|
jsonData = JSON.stringify(truncatedData);
|
|
838
|
-
console.log(`ā ļø Message truncated from ${data.text?.length} to ${truncatedData.text.length} chars`);
|
|
850
|
+
console.log(`ā ļø Message truncated .text from ${data.text?.length} to ${truncatedData.text.length} chars`);
|
|
851
|
+
}
|
|
852
|
+
// Also try truncating .content (research_artifact_content, plan_file_content)
|
|
853
|
+
if (jsonData.length > MAX_MESSAGE_SIZE && truncatedData.content && typeof truncatedData.content === 'string') {
|
|
854
|
+
const overhead = JSON.stringify({ ...truncatedData, content: '' }).length;
|
|
855
|
+
const maxContentLength = MAX_MESSAGE_SIZE - overhead - 100;
|
|
856
|
+
truncatedData.content = truncatedData.content.substring(0, maxContentLength) + '\n\n[Content truncated due to size limit]';
|
|
857
|
+
truncatedData.truncated = true;
|
|
858
|
+
truncatedData.originalSize = Buffer.byteLength(data.content, 'utf-8');
|
|
859
|
+
jsonData = JSON.stringify(truncatedData);
|
|
860
|
+
console.log(`ā ļø Message truncated .content from ${data.content?.length} to ${truncatedData.content.length} chars`);
|
|
839
861
|
}
|
|
840
862
|
}
|
|
863
|
+
// Hard cap ā if still too large after truncation, drop entirely.
|
|
864
|
+
// This prevents a 480KB base64 image or similar from killing the
|
|
865
|
+
// WebRTC publisher transport (which is unrecoverable without reconnect).
|
|
841
866
|
const payload = encoder.encode(jsonData);
|
|
867
|
+
if (payload.length > HARD_MAX_MESSAGE_SIZE) {
|
|
868
|
+
console.error(`ā sendToFrontend: dropping message (${(payload.length / 1024).toFixed(0)}KB > ${(HARD_MAX_MESSAGE_SIZE / 1024).toFixed(0)}KB hard limit) ā type: ${data.type}`);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
842
871
|
await localParticipant.publishData(payload, {
|
|
843
872
|
reliable: true,
|
|
844
873
|
topic: 'osborn-updates',
|
|
@@ -2677,13 +2706,42 @@ async function main() {
|
|
|
2677
2706
|
const fileName = filePath.split('/').pop() || '';
|
|
2678
2707
|
const ext = fileName.split('.').pop()?.toLowerCase() || '';
|
|
2679
2708
|
const isImage = ['png', 'jpg', 'jpeg', 'gif', 'webp'].includes(ext);
|
|
2709
|
+
// WebRTC SCTP data channel max message size is ~256KB. Sending
|
|
2710
|
+
// larger payloads corrupts the publisher transport, killing ALL
|
|
2711
|
+
// subsequent sends (publishData, streamBytes, publishTranscription)
|
|
2712
|
+
// with "could not establish publisher connection: timeout". This
|
|
2713
|
+
// was the root cause of the career-ops session bug: a 480KB
|
|
2714
|
+
// evaluation report blew through the limit on resume.
|
|
2715
|
+
// ā ļø MUST be low ā not just per-message but cumulative back-to-back pressure.
|
|
2716
|
+
// 12 artifact requests arrive simultaneously during session resume. Even if
|
|
2717
|
+
// each is individually "safe", flooding them kills the publisher PC. At 200KB
|
|
2718
|
+
// the search-index.txt (136KB) passed through and poisoned the connection.
|
|
2719
|
+
// 30KB catches search-index.txt (136KB), resume.pdf (233KB), and search-index-
|
|
2720
|
+
// meta.json (5.7KB passes). resume.html (14KB) also passes ā acceptable.
|
|
2721
|
+
const MAX_DATA_CHANNEL_BYTES = 30_000; // 30KB max per artifact
|
|
2680
2722
|
if (isImage) {
|
|
2681
|
-
const
|
|
2682
|
-
|
|
2723
|
+
const stats = fs.statSync(filePath);
|
|
2724
|
+
const base64Size = Math.ceil(stats.size * 4 / 3); // base64 inflates ~33%
|
|
2725
|
+
if (base64Size > MAX_DATA_CHANNEL_BYTES) {
|
|
2726
|
+
console.log(`ā ļø Artifact too large for data channel: ${fileName} (${(base64Size / 1024).toFixed(0)}KB base64) ā sending truncation notice`);
|
|
2727
|
+
await sendToFrontend({ type: 'research_artifact_content', filePath, content: '', fileName, isImage: false, truncated: true, originalSize: stats.size });
|
|
2728
|
+
}
|
|
2729
|
+
else {
|
|
2730
|
+
const base64 = fs.readFileSync(filePath, 'base64');
|
|
2731
|
+
await sendToFrontend({ type: 'research_artifact_content', filePath, content: base64, fileName, isImage: true, mimeType: `image/${ext}` });
|
|
2732
|
+
}
|
|
2683
2733
|
}
|
|
2684
2734
|
else {
|
|
2685
2735
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
2686
|
-
|
|
2736
|
+
if (Buffer.byteLength(content, 'utf-8') > MAX_DATA_CHANNEL_BYTES) {
|
|
2737
|
+
// Send a truncated preview + metadata so the frontend knows the file exists
|
|
2738
|
+
const truncated = content.substring(0, 5_000); // ~5KB preview (keep well under the 30KB limit)
|
|
2739
|
+
console.log(`ā ļø Artifact too large for data channel: ${fileName} (${(Buffer.byteLength(content, 'utf-8') / 1024).toFixed(0)}KB) ā sending truncated preview`);
|
|
2740
|
+
await sendToFrontend({ type: 'research_artifact_content', filePath, content: truncated, fileName, isImage: false, truncated: true, originalSize: Buffer.byteLength(content, 'utf-8') });
|
|
2741
|
+
}
|
|
2742
|
+
else {
|
|
2743
|
+
await sendToFrontend({ type: 'research_artifact_content', filePath, content, fileName, isImage: false });
|
|
2744
|
+
}
|
|
2687
2745
|
}
|
|
2688
2746
|
}
|
|
2689
2747
|
catch (err) {
|