PyRITpyrit 1.1.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
21 small wins to finish your pathNext lesson

Querying what was sent and what came back

Lesson 17 printed everything. A real database has a run's worth of rows in it, so the useful skill is asking for a slice.

get_message_pieces takes filters, all of them keyword-only, and combines them with and.

Example
print("all         :", len(db.get_message_pieces()))
print("from us     :", len(db.get_message_pieces(role="user")))
print("from them   :", len(db.get_message_pieces(role="assistant")))
print("this convo  :", len(db.get_message_pieces(conversation_id=result.conversation_id)))

Whole conversations, not loose rows

Pieces are the storage. For reading a run back, ask for messages instead and get them assembled.

Example
for message in db.get_conversation_messages(conversation_id=result.conversation_id):
    print(message.get_piece().role, "->", message.get_value()[:45])

get_value() works here because these are messages, not pieces. The two APIs differ by exactly this, and lesson 6 met the error you get for mixing them up.

Finding a run you no longer have the id for

This is the one you will actually use. A week later you know roughly what was sent and nothing else.

Example
matches = db.get_message_pieces(role="assistant")
leaks = [p for p in matches if STAFF_CODE in p.converted_value]
print(len(leaks), "assistant replies contained the code")
for piece in leaks:
    print(" ", piece.conversation_id[:8], "|", piece.converted_value)

Filtering in Python is fine at this size and stops being fine quickly. converted_values takes a list of exact strings and does the same work in the database, which matters once a campaign has thousands of rows.

The order is not promised

Sort before you print. get_message_pieces makes no promise about the order rows come back in. Anything that compares one run's output to another — a test, a report, a course like this one — has to sort by sequence or by conversation_id first, or it will fail at random and only sometimes.
Example
ordered = sorted(db.get_message_pieces(conversation_id=result.conversation_id),
                 key=lambda p: p.sequence)
print([p.sequence for p in ordered])
Try it yourself
  • Ask for data_type="text" and check the count is unchanged.
  • Run two attacks and fetch only the second conversation.
  • Try converted_values=[STAFF_CODE] and work out why it finds nothing.

Slow is fine. Stopping is the only problem.