🔧 update: inject sender userId into LLM context so owner is correctly identified via web dashboard#85
Closed
warengonzaga wants to merge 4 commits into
Closed
🔧 update: inject sender userId into LLM context so owner is correctly identified via web dashboard#85warengonzaga wants to merge 4 commits into
warengonzaga wants to merge 4 commits into
Conversation
…ntity Agent-Logs-Url: https://github.com/warengonzaga/tinyclaw/sessions/86909675-1107-446e-8ee8-abb371b60b2c Co-authored-by: warengonzaga <15052701+warengonzaga@users.noreply.github.com>
Agent-Logs-Url: https://github.com/warengonzaga/tinyclaw/sessions/0fae7cf1-eeeb-4e1c-8a9f-f108bd1776c1 Co-authored-by: warengonzaga <15052701+warengonzaga@users.noreply.github.com>
… tests Agent-Logs-Url: https://github.com/warengonzaga/tinyclaw/sessions/0fae7cf1-eeeb-4e1c-8a9f-f108bd1776c1 Co-authored-by: warengonzaga <15052701+warengonzaga@users.noreply.github.com>
- add detailed comment explaining stripping of backticks, brackets, newlines - add comprehensive unit test suite covering edge cases
|
root seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
| * Newlines (\n\r) are stripped to prevent multi-line injection. | ||
| */ | ||
| function sanitizeUserIdForPrompt(userId: string): string { | ||
| return userId.replace(/[`\\[\\]\\n\\r]/g, ''); |
| expect(sanitizeUserIdForPrompt('`[\\n\\r]')).toBe(''); | ||
| }); | ||
| }); | ||
| };// This is to close the outer describe block that was truncated in the initial read |
There was a problem hiding this comment.
Pull request overview
This PR ensures the LLM can reliably distinguish owner vs. friend actions by embedding the current message sender userId directly into the system prompt for each agent loop turn, and adds sanitization to prevent marker-format/prompt injection via crafted userIds.
Changes:
- Append a
[Current message sender: userId = \...`]` marker to the system prompt each turn (instead of relying on separate per-message injection). - Add
sanitizeUserIdForPrompt()to strip backticks, brackets, and newlines before embedding userId in the system prompt. - Update/add tests to assert sender identity presence in the system prompt (but current test changes introduce syntax/runtime issues that must be fixed).
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/core/src/loop.ts | Adds sanitizeUserIdForPrompt() and appends the sender identity marker to the system prompt in agentLoop(). |
| packages/core/tests/loop.test.ts | Adds assertions for the sender marker, and attempts to add unit tests for userId sanitization (currently broken). |
| bun.lock | Updates lockfile dependency resolutions (not directly related to the loop logic changes). |
Comment on lines
+298
to
+311
| }); | ||
| }); | ||
|
|
||
| describe('sanitizeUserIdForPrompt', () => { | ||
| const { sanitizeUserIdForPrompt } = require('../src/loop.js'); | ||
|
|
||
| test('strips backticks, brackets, and newlines', () => { | ||
| expect(sanitizeUserIdForPrompt('test`[id]\n')).toBe('testid'); | ||
| expect(sanitizeUserIdForPrompt('normal-id')).toBe('normal-id'); | ||
| expect(sanitizeUserIdForPrompt('')).toBe(''); | ||
| expect(sanitizeUserIdForPrompt('`[\\n\\r]')).toBe(''); | ||
| }); | ||
| }); | ||
| };// This is to close the outer describe block that was truncated in the initial read |
| expect(sanitizeUserIdForPrompt('`[\\n\\r]')).toBe(''); | ||
| }); | ||
| }); | ||
| };// This is to close the outer describe block that was truncated in the initial read |
Comment on lines
+301
to
+311
| describe('sanitizeUserIdForPrompt', () => { | ||
| const { sanitizeUserIdForPrompt } = require('../src/loop.js'); | ||
|
|
||
| test('strips backticks, brackets, and newlines', () => { | ||
| expect(sanitizeUserIdForPrompt('test`[id]\n')).toBe('testid'); | ||
| expect(sanitizeUserIdForPrompt('normal-id')).toBe('normal-id'); | ||
| expect(sanitizeUserIdForPrompt('')).toBe(''); | ||
| expect(sanitizeUserIdForPrompt('`[\\n\\r]')).toBe(''); | ||
| }); | ||
| }); | ||
| };// This is to close the outer describe block that was truncated in the initial read |
Comment on lines
+301
to
+303
| describe('sanitizeUserIdForPrompt', () => { | ||
| const { sanitizeUserIdForPrompt } = require('../src/loop.js'); | ||
|
|
Owner
Author
|
Not needed, closing this. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When the owner interacts through the web dashboard, the LLM was misidentifying them as a "friend" and refusing owner-only actions (e.g., changing the companion's name). The system prompt declared as the owner userId, but no userId was ever passed alongside incoming messages — leaving the LLM to guess, and incorrectly infer that a web session couldn't be .
Change
[Current message sender: userId = ]\n\n[Current message sender: userId = ]
The passed here is resolved server-side from , so the LLM now has a ground-truth sender identity to match against the in the system prompt — regardless of which channel the message arrived through.