comparison mrjunejune/test/conversation_api_test.js @ 265:056790c4fb0d

add role-aware Epi assistant prompts Add verified June knowledge, guest/member/admin Copilot profiles, profile-isolated session recovery, animated Epi greetings, and a single authoritative runtime config workflow for inference. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 10:50:30 -0700
parents 04fee26ecce0
children
comparison
equal deleted inserted replaced
264:04fee26ecce0 265:056790c4fb0d
165 ...process.env, 165 ...process.env,
166 MRJUNEJUNE_PORT: port, 166 MRJUNEJUNE_PORT: port,
167 MRJUNEJUNE_DB_PATH: databasePath, 167 MRJUNEJUNE_DB_PATH: databasePath,
168 MRJUNEJUNE_INFERENCE_SIDECAR_PATH: fakeSidecar, 168 MRJUNEJUNE_INFERENCE_SIDECAR_PATH: fakeSidecar,
169 MRJUNEJUNE_COPILOT_CLI_PATH: fakeSidecar, 169 MRJUNEJUNE_COPILOT_CLI_PATH: fakeSidecar,
170 MRJUNEJUNE_ALLOW_ANONYMOUS_INFERENCE: '1',
171 MRJUNEJUNE_ALLOW_GUEST_INFERENCE: '1', 170 MRJUNEJUNE_ALLOW_GUEST_INFERENCE: '1',
172 }, 171 },
173 stdio: ['ignore', 'pipe', 'pipe'], 172 stdio: ['ignore', 'pipe', 'pipe'],
174 }); 173 });
175 server.stdout.on('data', chunk => logs.push(chunk.toString())); 174 server.stdout.on('data', chunk => logs.push(chunk.toString()));
368 /^text\/event-stream/, 367 /^text\/event-stream/,
369 ); 368 );
370 const stream = await response.text(); 369 const stream = await response.text();
371 assert.match(stream, /event: turn\.accepted/); 370 assert.match(stream, /event: turn\.accepted/);
372 assert.match(stream, /event: tool\.started/); 371 assert.match(stream, /event: tool\.started/);
373 assert.match(stream, /"tool":\{"name":"mock-search"\}/); 372 assert.match(
373 stream,
374 /"tool":\{"name":"mock-search","prompt_profile":"public_visitor"\}/,
375 );
374 assert.match(stream, /event: assistant\.delta/); 376 assert.match(stream, /event: assistant\.delta/);
375 assert.match(stream, /hello \\"traveler\\"\\\\path/); 377 assert.match(stream, /hello \\"traveler\\"\\\\path/);
376 assert.match(stream, /event: assistant\.completed/); 378 assert.match(stream, /event: assistant\.completed/);
377 assert.match(stream, /event: assistant\.usage/); 379 assert.match(stream, /event: assistant\.usage/);
378 assert.match(stream, /event: turn\.done/); 380 assert.match(stream, /event: turn\.done/);
495 csrfToken: userCsrfC1, 497 csrfToken: userCsrfC1,
496 }), 498 }),
497 }); 499 });
498 assert.equal(loginR.status, 200, `Login must succeed, got ${loginR.status}`); 500 assert.equal(loginR.status, 200, `Login must succeed, got ${loginR.status}`);
499 const userCsrfC2 = await bootstrapSession(claimBase, userJarC); 501 const userCsrfC2 = await bootstrapSession(claimBase, userJarC);
502
503 const assertTurnProfile = async (jar, csrf, expectedProfile, title) => {
504 const createResponse = await authedFetch(
505 claimBase,
506 jar,
507 csrf,
508 '/api/conversations',
509 {
510 method: 'POST',
511 headers: { 'Content-Type': 'application/json', Origin: claimBase },
512 body: JSON.stringify({ title }),
513 },
514 );
515 assert.equal(createResponse.status, 201);
516 const createdConversation = await createResponse.json();
517 const turnResponse = await authedFetch(
518 claimBase,
519 jar,
520 csrf,
521 `/api/conversations/${createdConversation.id}/turns`,
522 {
523 method: 'POST',
524 headers: { 'Content-Type': 'application/json', Origin: claimBase },
525 body: JSON.stringify({ prompt: 'profile check' }),
526 },
527 );
528 assert.equal(turnResponse.status, 200);
529 assert.match(
530 await turnResponse.text(),
531 new RegExp(`"prompt_profile":"${expectedProfile}"`),
532 );
533 };
534
535 await assertTurnProfile(
536 userJarC,
537 userCsrfC2,
538 'june_admin',
539 'Admin profile',
540 );
541
542 const createMemberR = await authedFetch(
543 claimBase,
544 userJarC,
545 userCsrfC2,
546 '/api/admin/users',
547 {
548 method: 'POST',
549 headers: { 'Content-Type': 'application/json', Origin: claimBase },
550 body: JSON.stringify({
551 username: 'invitedfriend',
552 temporaryPassword: 'InvitedTempPass123!',
553 role: 'member',
554 }),
555 },
556 );
557 assert.equal(createMemberR.status, 201);
558
559 const memberJar = new CookieJar();
560 const memberGuestCsrf = await bootstrapSession(claimBase, memberJar);
561 const memberLoginR = await authedFetch(
562 claimBase,
563 memberJar,
564 memberGuestCsrf,
565 '/api/auth/login',
566 {
567 method: 'POST',
568 headers: { 'Content-Type': 'application/json', Origin: claimBase },
569 body: JSON.stringify({
570 username: 'invitedfriend',
571 password: 'InvitedTempPass123!',
572 csrfToken: memberGuestCsrf,
573 }),
574 },
575 );
576 assert.equal(memberLoginR.status, 200);
577 const memberLoginData = await memberLoginR.json();
578 assert.equal(memberLoginData.mustChangePassword, true);
579
580 const memberPasswordCsrf = await bootstrapSession(claimBase, memberJar);
581 const memberPasswordR = await authedFetch(
582 claimBase,
583 memberJar,
584 memberPasswordCsrf,
585 '/api/auth/password',
586 {
587 method: 'POST',
588 headers: { 'Content-Type': 'application/json', Origin: claimBase },
589 body: JSON.stringify({
590 currentPassword: 'InvitedTempPass123!',
591 newPassword: 'InvitedPermanentPass123!',
592 csrfToken: memberPasswordCsrf,
593 }),
594 },
595 );
596 assert.equal(memberPasswordR.status, 200);
597 const memberCsrf = await bootstrapSession(claimBase, memberJar);
598 await assertTurnProfile(
599 memberJar,
600 memberCsrf,
601 'invited_friend',
602 'Invited profile',
603 );
500 604
501 // A user cannot claim a conversation owned by a different guest. 605 // A user cannot claim a conversation owned by a different guest.
502 const claimR = await authedFetch(claimBase, userJarC, userCsrfC2, 606 const claimR = await authedFetch(claimBase, userJarC, userCsrfC2,
503 '/api/conversations/claim', 607 '/api/conversations/claim',
504 { 608 {