|
504 | 504 | expect(body[:result][:content]).to be_nil |
505 | 505 | end |
506 | 506 | end |
| 507 | + |
| 508 | + describe ".sampling_create_message" do |
| 509 | + # rubocop:disable RSpec/VerifiedDoubles |
| 510 | + let(:mock_content) do |
| 511 | + double("Content", text: "Hello, world!") |
| 512 | + end |
| 513 | + |
| 514 | + context "when message has no stop_reason" do |
| 515 | + let(:mock_message) do |
| 516 | + double( |
| 517 | + "Message", |
| 518 | + role: "assistant", |
| 519 | + content: mock_content |
| 520 | + ).tap do |msg| |
| 521 | + allow(msg).to receive(:respond_to?).with(:stop_reason).and_return(false) |
| 522 | + end |
| 523 | + end |
| 524 | + |
| 525 | + let(:body) do |
| 526 | + described_class::Responses.sampling_create_message( |
| 527 | + id: "req-123", |
| 528 | + message: mock_message, |
| 529 | + model: "gpt-4" |
| 530 | + ) |
| 531 | + end |
| 532 | + |
| 533 | + it "creates a valid sampling response with default stopReason" do |
| 534 | + expect(body[:jsonrpc]).to eq("2.0") |
| 535 | + expect(body[:id]).to eq("req-123") |
| 536 | + expect(body[:result][:role]).to eq("assistant") |
| 537 | + expect(body[:result][:model]).to eq("gpt-4") |
| 538 | + expect(body[:result][:stopReason]).to eq("endTurn") |
| 539 | + end |
| 540 | + |
| 541 | + it "validates against CreateMessageResult schema" do |
| 542 | + body_json = JSON.parse(body.to_json) |
| 543 | + response_json = { |
| 544 | + "jsonrpc" => "2.0", |
| 545 | + "id" => body_json["id"], |
| 546 | + "result" => body_json["result"] |
| 547 | + } |
| 548 | + errors = schemer.validate(response_json).to_a |
| 549 | + expect(errors).to be_empty, "Schema validation errors: #{errors.map(&:to_h)}" |
| 550 | + end |
| 551 | + end |
| 552 | + |
| 553 | + context "when message has stop_reason nil" do |
| 554 | + let(:mock_message) do |
| 555 | + double( |
| 556 | + "Message", |
| 557 | + role: "assistant", |
| 558 | + content: mock_content, |
| 559 | + stop_reason: nil |
| 560 | + ).tap do |msg| |
| 561 | + allow(msg).to receive(:respond_to?).with(:stop_reason).and_return(true) |
| 562 | + end |
| 563 | + end |
| 564 | + |
| 565 | + let(:body) do |
| 566 | + described_class::Responses.sampling_create_message( |
| 567 | + id: "req-123", |
| 568 | + message: mock_message, |
| 569 | + model: "gpt-4" |
| 570 | + ) |
| 571 | + end |
| 572 | + |
| 573 | + it "uses default stopReason when nil" do |
| 574 | + expect(body[:result][:stopReason]).to eq("endTurn") |
| 575 | + end |
| 576 | + end |
| 577 | + |
| 578 | + context "when message has stop_reason values" do |
| 579 | + shared_examples "converts stop_reason correctly" do |snake_case_value, camel_case_value| |
| 580 | + let(:mock_message) do |
| 581 | + double( |
| 582 | + "Message", |
| 583 | + role: "assistant", |
| 584 | + content: mock_content, |
| 585 | + stop_reason: snake_case_value |
| 586 | + ).tap do |msg| |
| 587 | + allow(msg).to receive(:respond_to?).with(:stop_reason).and_return(true) |
| 588 | + end |
| 589 | + end |
| 590 | + |
| 591 | + let(:body) do |
| 592 | + described_class::Responses.sampling_create_message( |
| 593 | + id: "req-123", |
| 594 | + message: mock_message, |
| 595 | + model: "gpt-4" |
| 596 | + ) |
| 597 | + end |
| 598 | + |
| 599 | + it "converts #{snake_case_value} to #{camel_case_value}" do |
| 600 | + expect(body[:result][:stopReason]).to eq(camel_case_value) |
| 601 | + end |
| 602 | + |
| 603 | + it "validates against CreateMessageResult schema" do |
| 604 | + body_json = JSON.parse(body.to_json) |
| 605 | + response_json = { |
| 606 | + "jsonrpc" => "2.0", |
| 607 | + "id" => body_json["id"], |
| 608 | + "result" => body_json["result"] |
| 609 | + } |
| 610 | + errors = schemer.validate(response_json).to_a |
| 611 | + expect(errors).to be_empty, "Schema validation errors: #{errors.map(&:to_h)}" |
| 612 | + end |
| 613 | + end |
| 614 | + |
| 615 | + context "with stop_reason: end_turn" do |
| 616 | + it_behaves_like "converts stop_reason correctly", "end_turn", "endTurn" |
| 617 | + end |
| 618 | + |
| 619 | + context "with stop_reason: max_tokens" do |
| 620 | + it_behaves_like "converts stop_reason correctly", "max_tokens", "maxTokens" |
| 621 | + end |
| 622 | + |
| 623 | + context "with stop_reason: stop_sequence" do |
| 624 | + it_behaves_like "converts stop_reason correctly", "stop_sequence", "stopSequence" |
| 625 | + end |
| 626 | + |
| 627 | + context "with stop_reason: tool_use" do |
| 628 | + it_behaves_like "converts stop_reason correctly", "tool_use", "toolUse" |
| 629 | + end |
| 630 | + |
| 631 | + context "with stop_reason: pause_turn" do |
| 632 | + it_behaves_like "converts stop_reason correctly", "pause_turn", "pauseTurn" |
| 633 | + end |
| 634 | + |
| 635 | + context "with stop_reason: refusal" do |
| 636 | + it_behaves_like "converts stop_reason correctly", "refusal", "refusal" |
| 637 | + end |
| 638 | + end |
| 639 | + |
| 640 | + context "with custom stop_reason values" do |
| 641 | + let(:mock_message) do |
| 642 | + double( |
| 643 | + "Message", |
| 644 | + role: "assistant", |
| 645 | + content: mock_content, |
| 646 | + stop_reason: "custom_stop_reason" |
| 647 | + ).tap do |msg| |
| 648 | + allow(msg).to receive(:respond_to?).with(:stop_reason).and_return(true) |
| 649 | + end |
| 650 | + end |
| 651 | + |
| 652 | + let(:body) do |
| 653 | + described_class::Responses.sampling_create_message( |
| 654 | + id: "req-123", |
| 655 | + message: mock_message, |
| 656 | + model: "gpt-4" |
| 657 | + ) |
| 658 | + end |
| 659 | + |
| 660 | + it "converts unknown snake_case values to camelCase" do |
| 661 | + expect(body[:result][:stopReason]).to eq("customStopReason") |
| 662 | + end |
| 663 | + end |
| 664 | + # rubocop:enable RSpec/VerifiedDoubles |
| 665 | + end |
507 | 666 | end |
508 | 667 |
|
509 | 668 | describe "UUID generation consistency" do |
|
0 commit comments