chore: officially migrate to submodule (#4502)
* remove apps/core and apps/fern * fix precommit * add submodule updates in workflows * submodule * remove core tests * update core revision * Add submodules: true to all GitHub workflows - Ensure all workflows can access git submodules - Add submodules support to deployment, test, and CI workflows - Fix YAML syntax issues in workflow files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * remove core-lint * upgrade core with latest main of oss --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,246 +0,0 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from letta.streaming_utils import JSONInnerThoughtsExtractor
|
||||
|
||||
|
||||
@pytest.mark.parametrize("wait_for_first_key", [True, False])
|
||||
def test_inner_thoughts_in_args_simple(wait_for_first_key):
|
||||
"""Test case where the function_delta.arguments contains inner_thoughts
|
||||
|
||||
Correct output should be inner_thoughts VALUE (not KEY) being written to one buffer
|
||||
And everything else (omiting inner_thoughts KEY) being written to the other buffer
|
||||
"""
|
||||
print("Running Test Case 1: With 'inner_thoughts'")
|
||||
handler1 = JSONInnerThoughtsExtractor(inner_thoughts_key="inner_thoughts", wait_for_first_key=wait_for_first_key)
|
||||
fragments1 = [
|
||||
"{",
|
||||
""""inner_thoughts":"Chad's x2 tradition""",
|
||||
" is going strong! 😂 I love the enthusiasm!",
|
||||
" Time to delve into something imaginative:",
|
||||
""" If you could swap lives with any fictional character for a day, who would it be?\"""",
|
||||
",",
|
||||
""""message":"Here we are again, with 'x2'!""",
|
||||
" 🎉 Let's take this chance: If you could swap",
|
||||
" lives with any fictional character for a day,",
|
||||
''' who would it be?"''',
|
||||
"}",
|
||||
]
|
||||
print("Basic inner thoughts testcase:", fragments1, "".join(fragments1))
|
||||
# Make sure the string is valid JSON
|
||||
_ = json.loads("".join(fragments1))
|
||||
|
||||
if wait_for_first_key:
|
||||
# If we're waiting for the first key, then the first opening brace should be buffered/held back
|
||||
# until after the inner thoughts are finished
|
||||
expected_updates1 = [
|
||||
{"main_json_update": "", "inner_thoughts_update": ""}, # Fragment 1 (NOTE: different)
|
||||
{"main_json_update": "", "inner_thoughts_update": "Chad's x2 tradition"}, # Fragment 2
|
||||
{"main_json_update": "", "inner_thoughts_update": " is going strong! 😂 I love the enthusiasm!"}, # Fragment 3
|
||||
{"main_json_update": "", "inner_thoughts_update": " Time to delve into something imaginative:"}, # Fragment 4
|
||||
{
|
||||
"main_json_update": "",
|
||||
"inner_thoughts_update": " If you could swap lives with any fictional character for a day, who would it be?",
|
||||
}, # Fragment 5
|
||||
{"main_json_update": "", "inner_thoughts_update": ""}, # Fragment 6 (comma after inner_thoughts)
|
||||
{
|
||||
"main_json_update": '{"message":"Here we are again, with \'x2\'!',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 7 (NOTE: the brace is included here, instead of at the beginning)
|
||||
{"main_json_update": " 🎉 Let's take this chance: If you could swap", "inner_thoughts_update": ""}, # Fragment 8
|
||||
{"main_json_update": " lives with any fictional character for a day,", "inner_thoughts_update": ""}, # Fragment 9
|
||||
{"main_json_update": ' who would it be?"', "inner_thoughts_update": ""}, # Fragment 10
|
||||
{"main_json_update": "}", "inner_thoughts_update": ""}, # Fragment 11
|
||||
]
|
||||
else:
|
||||
# If we're not waiting for the first key, then the first opening brace should be written immediately
|
||||
expected_updates1 = [
|
||||
{"main_json_update": "{", "inner_thoughts_update": ""}, # Fragment 1
|
||||
{"main_json_update": "", "inner_thoughts_update": "Chad's x2 tradition"}, # Fragment 2
|
||||
{"main_json_update": "", "inner_thoughts_update": " is going strong! 😂 I love the enthusiasm!"}, # Fragment 3
|
||||
{"main_json_update": "", "inner_thoughts_update": " Time to delve into something imaginative:"}, # Fragment 4
|
||||
{
|
||||
"main_json_update": "",
|
||||
"inner_thoughts_update": " If you could swap lives with any fictional character for a day, who would it be?",
|
||||
}, # Fragment 5
|
||||
{"main_json_update": "", "inner_thoughts_update": ""}, # Fragment 6 (comma after inner_thoughts)
|
||||
{"main_json_update": '"message":"Here we are again, with \'x2\'!', "inner_thoughts_update": ""}, # Fragment 7
|
||||
{"main_json_update": " 🎉 Let's take this chance: If you could swap", "inner_thoughts_update": ""}, # Fragment 8
|
||||
{"main_json_update": " lives with any fictional character for a day,", "inner_thoughts_update": ""}, # Fragment 9
|
||||
{"main_json_update": ' who would it be?"', "inner_thoughts_update": ""}, # Fragment 10
|
||||
{"main_json_update": "}", "inner_thoughts_update": ""}, # Fragment 11
|
||||
]
|
||||
|
||||
for idx, (fragment, expected) in enumerate(zip(fragments1, expected_updates1)):
|
||||
updates_main_json, updates_inner_thoughts = handler1.process_fragment(fragment)
|
||||
# Assertions
|
||||
assert updates_main_json == expected["main_json_update"], (
|
||||
f"Test Case 1, Fragment {idx + 1}: Main JSON update mismatch.\nExpected: '{expected['main_json_update']}'\nGot: '{updates_main_json}'"
|
||||
)
|
||||
assert updates_inner_thoughts == expected["inner_thoughts_update"], (
|
||||
f"Test Case 1, Fragment {idx + 1}: Inner Thoughts update mismatch.\nExpected: '{expected['inner_thoughts_update']}'\nGot: '{updates_inner_thoughts}'"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("wait_for_first_key", [True, False])
|
||||
def test_inner_thoughts_in_args_trailing_quote(wait_for_first_key):
|
||||
# Another test case where there's a function call that has a chunk that ends with a double quote
|
||||
print("Running Test Case: chunk ends with double quote")
|
||||
handler1 = JSONInnerThoughtsExtractor(inner_thoughts_key="inner_thoughts", wait_for_first_key=wait_for_first_key)
|
||||
fragments1 = [
|
||||
# 1
|
||||
"{",
|
||||
# 2
|
||||
"""\"inner_thoughts\":\"User wants to add 'banana' again for a fourth time; I'll track another addition.""",
|
||||
# 3
|
||||
'",',
|
||||
# 4
|
||||
"""\"content\":\"banana""",
|
||||
# 5
|
||||
"""\",\"""",
|
||||
# 6
|
||||
"""request_heartbeat\":\"""",
|
||||
# 7
|
||||
"""true\"""",
|
||||
# 8
|
||||
"}",
|
||||
]
|
||||
print("Double quote test case:", fragments1, "".join(fragments1))
|
||||
# Make sure the string is valid JSON
|
||||
_ = json.loads("".join(fragments1))
|
||||
|
||||
if wait_for_first_key:
|
||||
# If we're waiting for the first key, then the first opening brace should be buffered/held back
|
||||
# until after the inner thoughts are finished
|
||||
expected_updates1 = [
|
||||
{"main_json_update": "", "inner_thoughts_update": ""}, # Fragment 1 (NOTE: different)
|
||||
{
|
||||
"main_json_update": "",
|
||||
"inner_thoughts_update": "User wants to add 'banana' again for a fourth time; I'll track another addition.",
|
||||
}, # Fragment 2
|
||||
{"main_json_update": "", "inner_thoughts_update": ""}, # Fragment 3
|
||||
{
|
||||
"main_json_update": '{"content":"banana',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 4
|
||||
{
|
||||
# "main_json_update": '","',
|
||||
"main_json_update": '",',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 5
|
||||
{
|
||||
# "main_json_update": 'request_heartbeat":"',
|
||||
"main_json_update": '"request_heartbeat":"',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 6
|
||||
{
|
||||
"main_json_update": 'true"',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 7
|
||||
{
|
||||
"main_json_update": "}",
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 8
|
||||
]
|
||||
else:
|
||||
pass
|
||||
# If we're not waiting for the first key, then the first opening brace should be written immediately
|
||||
expected_updates1 = [
|
||||
{"main_json_update": "{", "inner_thoughts_update": ""}, # Fragment 1 (NOTE: different)
|
||||
{
|
||||
"main_json_update": "",
|
||||
"inner_thoughts_update": "User wants to add 'banana' again for a fourth time; I'll track another addition.",
|
||||
}, # Fragment 2
|
||||
{"main_json_update": "", "inner_thoughts_update": ""}, # Fragment 3
|
||||
{
|
||||
"main_json_update": '"content":"banana',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 4
|
||||
{
|
||||
# "main_json_update": '","',
|
||||
"main_json_update": '",',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 5
|
||||
{
|
||||
# "main_json_update": 'request_heartbeat":"',
|
||||
"main_json_update": '"request_heartbeat":"',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 6
|
||||
{
|
||||
"main_json_update": 'true"',
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 7
|
||||
{
|
||||
"main_json_update": "}",
|
||||
"inner_thoughts_update": "",
|
||||
}, # Fragment 8
|
||||
]
|
||||
|
||||
current_inner_thoughts = ""
|
||||
current_main_json = ""
|
||||
for idx, (fragment, expected) in enumerate(zip(fragments1, expected_updates1)):
|
||||
updates_main_json, updates_inner_thoughts = handler1.process_fragment(fragment)
|
||||
# Assertions
|
||||
assert updates_main_json == expected["main_json_update"], (
|
||||
f"Test Case 1, Fragment {idx + 1}: Main JSON update mismatch.\nFragment: '{fragment}'\nExpected: '{expected['main_json_update']}'\nGot: '{updates_main_json}'\nCurrent JSON: '{current_main_json}'\nCurrent Inner Thoughts: '{current_inner_thoughts}'"
|
||||
)
|
||||
assert updates_inner_thoughts == expected["inner_thoughts_update"], (
|
||||
f"Test Case 1, Fragment {idx + 1}: Inner Thoughts update mismatch.\nExpected: '{expected['inner_thoughts_update']}'\nGot: '{updates_inner_thoughts}'\nCurrent JSON: '{current_main_json}'\nCurrent Inner Thoughts: '{current_inner_thoughts}'"
|
||||
)
|
||||
current_main_json += updates_main_json
|
||||
current_inner_thoughts += updates_inner_thoughts
|
||||
|
||||
print(f"Final JSON: '{current_main_json}'")
|
||||
print(f"Final Inner Thoughts: '{current_inner_thoughts}'")
|
||||
_ = json.loads(current_main_json)
|
||||
|
||||
|
||||
def test_inner_thoughts_not_in_args():
|
||||
"""Test case where the function_delta.arguments does not contain inner_thoughts
|
||||
|
||||
Correct output should be everything being written to the main_json buffer
|
||||
"""
|
||||
print("Running Test Case 2: Without 'inner_thoughts'")
|
||||
handler2 = JSONInnerThoughtsExtractor(inner_thoughts_key="inner_thoughts")
|
||||
fragments2 = [
|
||||
"{",
|
||||
""""message":"Here we are again, with 'x2'!""",
|
||||
" 🎉 Let's take this chance: If you could swap",
|
||||
" lives with any fictional character for a day,",
|
||||
''' who would it be?"''',
|
||||
"}",
|
||||
]
|
||||
print("Basic inner thoughts not in kwargs testcase:", fragments2, "".join(fragments2))
|
||||
# Make sure the string is valid JSON
|
||||
_ = json.loads("".join(fragments2))
|
||||
|
||||
expected_updates2 = [
|
||||
{"main_json_update": "{", "inner_thoughts_update": ""}, # Fragment 1
|
||||
{"main_json_update": '"message":"Here we are again, with \'x2\'!', "inner_thoughts_update": ""}, # Fragment 2
|
||||
{"main_json_update": " 🎉 Let's take this chance: If you could swap", "inner_thoughts_update": ""}, # Fragment 3
|
||||
{"main_json_update": " lives with any fictional character for a day,", "inner_thoughts_update": ""}, # Fragment 4
|
||||
{"main_json_update": ' who would it be?"', "inner_thoughts_update": ""}, # Fragment 5
|
||||
{"main_json_update": "}", "inner_thoughts_update": ""}, # Fragment 6
|
||||
]
|
||||
|
||||
for idx, (fragment, expected) in enumerate(zip(fragments2, expected_updates2)):
|
||||
updates_main_json, updates_inner_thoughts = handler2.process_fragment(fragment)
|
||||
# Assertions
|
||||
assert updates_main_json == expected["main_json_update"], (
|
||||
f"Test Case 2, Fragment {idx + 1}: Main JSON update mismatch.\nExpected: '{expected['main_json_update']}'\nGot: '{updates_main_json}'"
|
||||
)
|
||||
assert updates_inner_thoughts == expected["inner_thoughts_update"], (
|
||||
f"Test Case 2, Fragment {idx + 1}: Inner Thoughts update mismatch.\nExpected: '{expected['inner_thoughts_update']}'\nGot: '{updates_inner_thoughts}'"
|
||||
)
|
||||
|
||||
# Final assertions for Test Case 2
|
||||
expected_final_main_json2 = '{"message":"Here we are again, with \'x2\'! 🎉 Let\'s take this chance: If you could swap lives with any fictional character for a day, who would it be?"}'
|
||||
expected_final_inner_thoughts2 = ""
|
||||
|
||||
assert handler2.main_json == expected_final_main_json2, (
|
||||
f"Test Case 2: Final main_json mismatch.\nExpected: '{expected_final_main_json2}'\nGot: '{handler2.main_json}'"
|
||||
)
|
||||
assert handler2.inner_thoughts == expected_final_inner_thoughts2, (
|
||||
f"Test Case 2: Final inner_thoughts mismatch.\nExpected: '{expected_final_inner_thoughts2}'\nGot: '{handler2.inner_thoughts}'"
|
||||
)
|
||||
Reference in New Issue
Block a user