zai-adk-python-preview 0.1.3__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/.gitignore +4 -1
  2. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/PKG-INFO +46 -1
  3. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/README.md +45 -0
  4. zai_adk_python_preview-0.1.4/examples/test_streaming.py +110 -0
  5. zai_adk_python_preview-0.1.4/examples/test_streaming_real.py +450 -0
  6. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/pyproject.toml +1 -1
  7. zai_adk_python_preview-0.1.4/tests/test_streaming_e2e.py +304 -0
  8. zai_adk_python_preview-0.1.4/tests/unit/agui/test_streaming_converter.py +98 -0
  9. zai_adk_python_preview-0.1.4/tests/unit/llm/test_stream.py +103 -0
  10. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/uv.lock +2 -2
  11. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/agent/events.py +51 -1
  12. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/agent/service.py +79 -9
  13. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/anthropic/chat.py +87 -0
  14. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/base.py +35 -0
  15. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/openai/chat.py +140 -45
  16. zai_adk_python_preview-0.1.4/zai_adk/llm/stream.py +109 -0
  17. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/agui/converter.py +68 -13
  18. zai_adk_python_preview-0.1.3/.claude/settings.local.json +0 -37
  19. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/.gitlab-ci.yml +0 -0
  20. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/CLAUDE.md +0 -0
  21. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/LICENSE +0 -0
  22. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/README_zh.md +0 -0
  23. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/agui.md +0 -0
  24. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2025-02-02-reorganize-tests.md +0 -0
  25. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2025-02-02-skill-reference-fix.md +0 -0
  26. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-01-29-sandbox.md +0 -0
  27. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-01-30-built-in-tools.md +0 -0
  28. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-01-30-skill-filesystem-enhancement.md +0 -0
  29. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-02-skills-optimization.md +0 -0
  30. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-02-subagent-implementation.md +0 -0
  31. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-02-test-reorganization.md +0 -0
  32. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-03-ag-ui-protocol-support.md +0 -0
  33. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-03-default-sandbox.md +0 -0
  34. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-04-agui-missing-events.md +0 -0
  35. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-04-protocol-layer-refactor.md +0 -0
  36. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/plans/2026-02-04-remove-agui-from-agent.md +0 -0
  37. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/protocols.md +0 -0
  38. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/docs/sandbox.md +0 -0
  39. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/examples/claude_code.py +0 -0
  40. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/README.md +0 -0
  41. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/conftest.py +0 -0
  42. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/__init__.py +0 -0
  43. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/agent/__init__.py +0 -0
  44. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/agent/test_agent_query.py +0 -0
  45. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/agent/test_default_sandbox_integration.py +0 -0
  46. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/agent/test_subagent_integration.py +0 -0
  47. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/agui/__init__.py +0 -0
  48. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/agui/test_agui_integration.py +0 -0
  49. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/llm/__init__.py +0 -0
  50. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/llm/test_anthropic_chat.py +0 -0
  51. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/llm/test_openai_chat.py +0 -0
  52. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/skills/__init__.py +0 -0
  53. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/skills/test_skills_end_to_end.py +0 -0
  54. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/skills/test_skills_live.py +0 -0
  55. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/tools/__init__.py +0 -0
  56. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/integration/tools/test_tools_integration.py +0 -0
  57. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/__init__.py +0 -0
  58. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/__init__.py +0 -0
  59. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_agent.py +0 -0
  60. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_agent_sandbox.py +0 -0
  61. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_agent_template.py +0 -0
  62. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_agent_templates.py +0 -0
  63. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_async_initialization.py +0 -0
  64. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_delegate_task.py +0 -0
  65. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_dependencies.py +0 -0
  66. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_sandbox_integration.py +0 -0
  67. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_skills_hot_reload.py +0 -0
  68. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_skills_injection.py +0 -0
  69. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_skills_integration.py +0 -0
  70. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_subagent_types.py +0 -0
  71. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agent/test_subagent_unit.py +0 -0
  72. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/__init__.py +0 -0
  73. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_agent_integration.py +0 -0
  74. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_converter.py +0 -0
  75. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_encoder.py +0 -0
  76. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_error_handling.py +0 -0
  77. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_events.py +0 -0
  78. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_protocol.py +0 -0
  79. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/agui/test_thinking_events.py +0 -0
  80. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/compaction/__init__.py +0 -0
  81. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/compaction/test_compaction.py +0 -0
  82. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/mcp/__init__.py +0 -0
  83. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/mcp/test_client.py +0 -0
  84. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/mcp/test_config.py +0 -0
  85. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/protocols/__init__.py +0 -0
  86. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/protocols/test_base.py +0 -0
  87. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/sandbox/__init__.py +0 -0
  88. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/sandbox/test_base.py +0 -0
  89. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/sandbox/test_factory.py +0 -0
  90. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/sandbox/test_local.py +0 -0
  91. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/sandbox/test_sandbox_config.py +0 -0
  92. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/__init__.py +0 -0
  93. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/test_manager.py +0 -0
  94. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/test_manager_filesystem.py +0 -0
  95. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/test_manager_logging.py +0 -0
  96. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/test_parser.py +0 -0
  97. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/test_types.py +0 -0
  98. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/skills/test_xml_generator.py +0 -0
  99. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/todo/__init__.py +0 -0
  100. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/todo/test_service.py +0 -0
  101. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tokens/__init__.py +0 -0
  102. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tokens/test_tokens.py +0 -0
  103. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/__init__.py +0 -0
  104. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_fs_edit.py +0 -0
  105. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_fs_grep.py +0 -0
  106. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_sandbox_tools.py +0 -0
  107. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_skill_exec_tool.py +0 -0
  108. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_skills_tool.py +0 -0
  109. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_task_run_tool.py +0 -0
  110. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/tests/unit/tools/test_todo_tools.py +0 -0
  111. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/__init__.py +0 -0
  112. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/agent/__init__.py +0 -0
  113. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/agent/types.py +0 -0
  114. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/context/__init__.py +0 -0
  115. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/context/compaction.py +0 -0
  116. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/context/models.py +0 -0
  117. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/__init__.py +0 -0
  118. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/anthropic/serializer.py +0 -0
  119. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/exceptions.py +0 -0
  120. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/messages.py +0 -0
  121. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/openai/serializer.py +0 -0
  122. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/schema.py +0 -0
  123. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/llm/views.py +0 -0
  124. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/mcp/__init__.py +0 -0
  125. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/mcp/client.py +0 -0
  126. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/mcp/config.py +0 -0
  127. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/observability/__init__.py +0 -0
  128. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/observability/observability.py +0 -0
  129. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/__init__.py +0 -0
  130. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/agui/__init__.py +0 -0
  131. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/agui/encoder.py +0 -0
  132. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/agui/events.py +0 -0
  133. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/agui/protocol.py +0 -0
  134. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/protocols/base.py +0 -0
  135. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/sandbox/__init__.py +0 -0
  136. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/sandbox/base.py +0 -0
  137. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/sandbox/config.py +0 -0
  138. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/sandbox/factory.py +0 -0
  139. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/sandbox/local.py +0 -0
  140. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/skills/__init__.py +0 -0
  141. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/skills/manager.py +0 -0
  142. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/skills/parser.py +0 -0
  143. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/skills/types.py +0 -0
  144. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/skills/xml_generator.py +0 -0
  145. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/todo/__init__.py +0 -0
  146. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/todo/service.py +0 -0
  147. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tokens/__init__.py +0 -0
  148. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tokens/custom_pricing.py +0 -0
  149. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tokens/mappings.py +0 -0
  150. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tokens/service.py +0 -0
  151. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tokens/views.py +0 -0
  152. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/__init__.py +0 -0
  153. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/__init__.py +0 -0
  154. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/bash.py +0 -0
  155. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/fs_edit.py +0 -0
  156. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/fs_glob.py +0 -0
  157. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/fs_grep.py +0 -0
  158. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/fs_read.py +0 -0
  159. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/fs_stat.py +0 -0
  160. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/fs_write.py +0 -0
  161. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/skill_exec.py +0 -0
  162. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/skills.py +0 -0
  163. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/task_run.py +0 -0
  164. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/builtin/todo.py +0 -0
  165. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/decorator.py +0 -0
  166. {zai_adk_python_preview-0.1.3 → zai_adk_python_preview-0.1.4}/zai_adk/tools/depends.py +0 -0
@@ -217,4 +217,7 @@ __marimo__/
217
217
 
218
218
  # Streamlit
219
219
  .streamlit/secrets.toml
220
- ./tmp/
220
+ ./tmp/
221
+ # Claude Code / OMC
222
+ .claude/
223
+ .omc/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zai-adk-python-preview
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: A Python SDK for building AI agents with LLM integration
5
5
  Project-URL: Homepage, https://github.com/zai-adk-python/zai-adk-python
6
6
  Project-URL: Documentation, https://github.com/zai-adk-python/zai-adk-python#readme
@@ -139,6 +139,51 @@ async for event in agent.query_stream("Help me with a task"):
139
139
  print(f"[Final]: {text}")
140
140
  ```
141
141
 
142
+ ### True Token Streaming
143
+
144
+ Enable real-time token-by-token streaming from the LLM with `stream=True`:
145
+
146
+ ```python
147
+ from zai_adk.agent import TextChunkEvent, ThinkingChunkEvent, FinalResponseEvent
148
+
149
+ async for event in agent.query_stream("Explain quantum computing", stream=True):
150
+ match event:
151
+ case ThinkingChunkEvent(content=delta):
152
+ print(delta, end="", flush=True) # thinking token delta
153
+ case TextChunkEvent(content=delta):
154
+ print(delta, end="", flush=True) # text token delta
155
+ case FinalResponseEvent(content=text):
156
+ print(f"\nDone: {text}")
157
+ ```
158
+
159
+ **Key differences from default (`stream=False`):**
160
+
161
+ | | `stream=False` (default) | `stream=True` |
162
+ |---|---|---|
163
+ | First token latency | Waits for full response | Streams immediately |
164
+ | Event types | `TextEvent` (complete text) | `TextChunkEvent` per token + `TextEvent` (complete) |
165
+ | Thinking | `ThinkingEvent` (complete) | `ThinkingChunkEvent` per token + `ThinkingEvent` (complete) |
166
+ | Backward compat | — | Fully compatible, same tool execution flow |
167
+
168
+ **Enable extended thinking (GLM, DeepSeek):**
169
+
170
+ ```python
171
+ from zai_adk.llm.openai.chat import ChatOpenAI
172
+
173
+ llm = ChatOpenAI(
174
+ model="glm-5.1",
175
+ thinking={"type": "enabled"}, # enable reasoning output
176
+ )
177
+ agent = Agent(llm=llm, tools=[])
178
+
179
+ async for event in agent.query_stream("Think carefully: 9.11 vs 9.8", stream=True):
180
+ match event:
181
+ case ThinkingChunkEvent(content=delta):
182
+ print(f"[think] {delta}", end="", flush=True)
183
+ case TextChunkEvent(content=delta):
184
+ print(delta, end="", flush=True)
185
+ ```
186
+
142
187
  ### Sandboxed File Operations
143
188
 
144
189
  ```python
@@ -89,6 +89,51 @@ async for event in agent.query_stream("Help me with a task"):
89
89
  print(f"[Final]: {text}")
90
90
  ```
91
91
 
92
+ ### True Token Streaming
93
+
94
+ Enable real-time token-by-token streaming from the LLM with `stream=True`:
95
+
96
+ ```python
97
+ from zai_adk.agent import TextChunkEvent, ThinkingChunkEvent, FinalResponseEvent
98
+
99
+ async for event in agent.query_stream("Explain quantum computing", stream=True):
100
+ match event:
101
+ case ThinkingChunkEvent(content=delta):
102
+ print(delta, end="", flush=True) # thinking token delta
103
+ case TextChunkEvent(content=delta):
104
+ print(delta, end="", flush=True) # text token delta
105
+ case FinalResponseEvent(content=text):
106
+ print(f"\nDone: {text}")
107
+ ```
108
+
109
+ **Key differences from default (`stream=False`):**
110
+
111
+ | | `stream=False` (default) | `stream=True` |
112
+ |---|---|---|
113
+ | First token latency | Waits for full response | Streams immediately |
114
+ | Event types | `TextEvent` (complete text) | `TextChunkEvent` per token + `TextEvent` (complete) |
115
+ | Thinking | `ThinkingEvent` (complete) | `ThinkingChunkEvent` per token + `ThinkingEvent` (complete) |
116
+ | Backward compat | — | Fully compatible, same tool execution flow |
117
+
118
+ **Enable extended thinking (GLM, DeepSeek):**
119
+
120
+ ```python
121
+ from zai_adk.llm.openai.chat import ChatOpenAI
122
+
123
+ llm = ChatOpenAI(
124
+ model="glm-5.1",
125
+ thinking={"type": "enabled"}, # enable reasoning output
126
+ )
127
+ agent = Agent(llm=llm, tools=[])
128
+
129
+ async for event in agent.query_stream("Think carefully: 9.11 vs 9.8", stream=True):
130
+ match event:
131
+ case ThinkingChunkEvent(content=delta):
132
+ print(f"[think] {delta}", end="", flush=True)
133
+ case TextChunkEvent(content=delta):
134
+ print(delta, end="", flush=True)
135
+ ```
136
+
92
137
  ### Sandboxed File Operations
93
138
 
94
139
  ```python
@@ -0,0 +1,110 @@
1
+ """Quick manual test for true streaming vs pseudo-streaming.
2
+
3
+ Usage:
4
+ uv run python -m examples.test_streaming
5
+
6
+ Compare the output of stream=False vs stream=True:
7
+ - stream=False: you wait several seconds, then see the full text at once
8
+ - stream=True: you see text appear token-by-token in real time
9
+ """
10
+
11
+ import asyncio
12
+ import time
13
+
14
+ from zai_adk import Agent
15
+ from zai_adk.llm.openai.chat import ChatOpenAI
16
+
17
+
18
+ async def test_stream_false():
19
+ """Default behavior — collect full response then yield."""
20
+ llm = ChatOpenAI(
21
+ model="glm-4.7",
22
+ temperature=0.3,
23
+ max_completion_tokens=256,
24
+ )
25
+ agent = Agent(llm=llm, tools=[])
26
+
27
+ print("=" * 60)
28
+ print("stream=False (pseudo-streaming)")
29
+ print("=" * 60)
30
+
31
+ start = time.time()
32
+ async for event in agent.query_stream("用一句话介绍什么是量子计算"):
33
+ if hasattr(event, "content") and event.content:
34
+ elapsed = time.time() - start
35
+ print(f" [{elapsed:.2f}s] {type(event).__name__}: {event.content[:80]}")
36
+ print()
37
+
38
+
39
+ async def test_stream_true():
40
+ """True streaming — token by token."""
41
+ llm = ChatOpenAI(
42
+ model="glm-4.7",
43
+ temperature=0.3,
44
+ max_completion_tokens=256,
45
+ )
46
+ agent = Agent(llm=llm, tools=[])
47
+
48
+ print("=" * 60)
49
+ print("stream=True (true streaming)")
50
+ print("=" * 60)
51
+
52
+ start = time.time()
53
+ full_text = []
54
+ async for event in agent.query_stream("用一句话介绍什么是量子计算", stream=True):
55
+ match event:
56
+ case _ if hasattr(event, "content") and isinstance(event.content, str) and event.content:
57
+ elapsed = time.time() - start
58
+ type_name = type(event).__name__
59
+ if type_name == "TextChunkEvent":
60
+ print(event.content, end="", flush=True)
61
+ full_text.append(event.content)
62
+ else:
63
+ print(f"\n [{elapsed:.2f}s] {type_name}: {event.content[:80]}")
64
+ print(f"\n Full text length: {len(''.join(full_text))} chars")
65
+ print()
66
+
67
+
68
+ async def test_stream_with_tools():
69
+ """True streaming with tool calls."""
70
+ from zai_adk.tools.builtin import bash
71
+
72
+ llm = ChatOpenAI(
73
+ model="glm-4.7",
74
+ temperature=0.3,
75
+ max_completion_tokens=256,
76
+ )
77
+ agent = Agent(llm=llm, tools=[bash])
78
+
79
+ print("=" * 60)
80
+ print("stream=True with tool calls")
81
+ print("=" * 60)
82
+
83
+ start = time.time()
84
+ async for event in agent.query_stream("列出当前目录下的 Python 文件", stream=True):
85
+ match event:
86
+ case _ if hasattr(event, "content") and isinstance(event.content, str) and event.content:
87
+ type_name = type(event).__name__
88
+ if type_name == "TextChunkEvent":
89
+ print(event.content, end="", flush=True)
90
+ else:
91
+ elapsed = time.time() - start
92
+ print(f"\n [{elapsed:.2f}s] {type_name}: {event.content[:80]}")
93
+ print("\n")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ import os
98
+
99
+ if not os.getenv("OPENAI_API_KEY") and not os.getenv("OPENAI_BASE_URL"):
100
+ print("Please set OPENAI_API_KEY or OPENAI_BASE_URL in .env")
101
+ exit(1)
102
+
103
+ print("\n>>> Test 1: Pseudo-streaming (default)")
104
+ asyncio.run(test_stream_false())
105
+
106
+ print("\n>>> Test 2: True streaming")
107
+ asyncio.run(test_stream_true())
108
+
109
+ print("\n>>> Test 3: True streaming with tools")
110
+ asyncio.run(test_stream_with_tools())
@@ -0,0 +1,450 @@
1
+ """
2
+ True streaming real API test — covers text, tools, and skills.
3
+
4
+ Usage:
5
+ # Edit .env with your API credentials, then:
6
+ uv run python -m examples.test_streaming_real
7
+
8
+ # Or set env vars directly:
9
+ OPENAI_API_KEY=your-key OPENAI_BASE_URL=https://... uv run python -m examples.test_streaming_real
10
+ """
11
+
12
+ import asyncio
13
+ import os
14
+ import sys
15
+ import time
16
+ from pathlib import Path
17
+
18
+ from dotenv import load_dotenv
19
+
20
+ load_dotenv()
21
+
22
+ from zai_adk import Agent
23
+ from zai_adk.agent.events import (
24
+ FinalResponseEvent,
25
+ TextChunkEvent,
26
+ TextEvent,
27
+ ThinkingChunkEvent,
28
+ ToolCallEvent,
29
+ ToolResultEvent,
30
+ )
31
+ from zai_adk.llm.openai.chat import ChatOpenAI
32
+ from zai_adk.sandbox import SandboxConfig
33
+ from zai_adk.tools.builtin import bash, fs_read, fs_write, fs_glob, fs_grep
34
+ from zai_adk.tools.decorator import tool
35
+
36
+
37
+ # ─── Custom tools ───────────────────────────────────────────────────────────
38
+
39
+ @tool("Calculate the result of a math expression")
40
+ async def calculator(expression: str) -> str:
41
+ """Safely evaluate a math expression."""
42
+ import ast
43
+ import operator
44
+
45
+ ops = {
46
+ ast.Add: operator.add, ast.Sub: operator.sub,
47
+ ast.Mult: operator.mul, ast.Div: operator.truediv,
48
+ ast.Pow: operator.pow, ast.USub: operator.neg,
49
+ }
50
+
51
+ def _eval(node):
52
+ if isinstance(node, ast.Constant):
53
+ return node.value
54
+ if isinstance(node, ast.UnaryOp):
55
+ return ops[type(node.op)](_eval(node.operand))
56
+ if isinstance(node, ast.BinOp):
57
+ return ops[type(node.op)](_eval(node.left), _eval(node.right))
58
+ raise ValueError(f"Unsupported: {type(node).__name__}")
59
+
60
+ try:
61
+ result = _eval(ast.parse(expression, mode="eval").body)
62
+ return str(result)
63
+ except Exception as e:
64
+ return f"Error: {e}"
65
+
66
+
67
+ @tool("Get the current time")
68
+ async def get_time() -> str:
69
+ from datetime import datetime
70
+ return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
71
+
72
+
73
+ # ─── LLM setup ─────────────────────────────────────────────────────────────
74
+
75
+ def create_llm(thinking: bool = False):
76
+ api_key = os.getenv("OPENAI_API_KEY")
77
+ base_url = os.getenv("OPENAI_BASE_URL")
78
+ model = os.getenv("OPENAI_MODEL", "glm-4.7")
79
+
80
+ if not api_key and not base_url:
81
+ print("ERROR: Set OPENAI_API_KEY or OPENAI_BASE_URL in .env or environment")
82
+ sys.exit(1)
83
+
84
+ return ChatOpenAI(
85
+ model=model,
86
+ api_key=api_key,
87
+ base_url=base_url,
88
+ temperature=0.3,
89
+ max_completion_tokens=2048,
90
+ thinking={"type": "enabled"} if thinking else None,
91
+ )
92
+
93
+
94
+ # ─── Color helpers ──────────────────────────────────────────────────────────
95
+
96
+ class C:
97
+ """ANSI colors for terminal output."""
98
+ BOLD = "\033[1m"
99
+ DIM = "\033[2m"
100
+ CYAN = "\033[36m"
101
+ GREEN = "\033[32m"
102
+ YELLOW = "\033[33m"
103
+ BLUE = "\033[34m"
104
+ MAGENTA = "\033[35m"
105
+ RED = "\033[31m"
106
+ RESET = "\033[0m"
107
+
108
+
109
+ def header(title: str):
110
+ print(f"\n{'=' * 70}")
111
+ print(f" {C.BOLD}{C.CYAN}{title}{C.RESET}")
112
+ print(f"{'=' * 70}\n")
113
+
114
+
115
+ # ─── Test cases ─────────────────────────────────────────────────────────────
116
+
117
+ async def test_1_text_only_streaming():
118
+ """Test 1: Pure text streaming — compare stream=False vs stream=True."""
119
+ header("Test 1: Text-only streaming comparison")
120
+ tools = []
121
+ prompt = "用三句话解释什么是大语言模型(LLM)。"
122
+
123
+ # --- stream=False (pseudo-streaming) ---
124
+ agent = Agent(llm=create_llm(), tools=tools)
125
+ print(f" {C.DIM}[stream=False] Waiting for full response...{C.RESET}")
126
+ start = time.time()
127
+ first_token_time = None
128
+ async for event in agent.query_stream(prompt, stream=False):
129
+ if isinstance(event, TextEvent):
130
+ first_token_time = time.time() - start
131
+ print(f" {C.GREEN}TextEvent (full): {event.content[:60]}...{C.RESET}")
132
+ elif isinstance(event, FinalResponseEvent):
133
+ total_time = time.time() - start
134
+ print(f" {C.DIM}First token: {first_token_time:.2f}s | Total: {total_time:.2f}s{C.RESET}")
135
+
136
+ # --- stream=True (true streaming) ---
137
+ agent = Agent(llm=create_llm(), tools=tools)
138
+ print(f"\n {C.DIM}[stream=True] Streaming token by token...{C.RESET}")
139
+ start = time.time()
140
+ first_chunk_time = None
141
+ chunk_count = 0
142
+ full_text = []
143
+ print(f" {C.YELLOW}", end="", flush=True)
144
+ async for event in agent.query_stream(prompt, stream=True):
145
+ if isinstance(event, TextChunkEvent):
146
+ if first_chunk_time is None:
147
+ first_chunk_time = time.time() - start
148
+ chunk_count += 1
149
+ full_text.append(event.content)
150
+ print(event.content, end="", flush=True)
151
+ elif isinstance(event, TextEvent):
152
+ pass # complete text, already printed via chunks
153
+ elif isinstance(event, FinalResponseEvent):
154
+ total_time = time.time() - start
155
+ print(f"{C.RESET}")
156
+ print(f" {C.DIM}Chunks: {chunk_count} | First token: {first_chunk_time:.2f}s | Total: {total_time:.2f}s{C.RESET}")
157
+ print(f" {C.DIM}Full text: {''.join(full_text)[:80]}...{C.RESET}")
158
+
159
+
160
+ async def test_2_builtin_tools():
161
+ """Test 2: Streaming with built-in tools (bash, fs_glob, fs_read)."""
162
+ header("Test 2: Streaming with built-in tools")
163
+ workspace = str(Path(__file__).parent.parent) # project root
164
+ tools = [bash, fs_glob, fs_read]
165
+ prompt = f"列出 {workspace}/zai_adk/llm/ 目录下的所有 Python 文件,并读取 base.py 的前 5 行。"
166
+
167
+ agent = Agent(
168
+ llm=create_llm(),
169
+ tools=tools,
170
+ sandbox=SandboxConfig(kind="local", work_dir=workspace),
171
+ )
172
+
173
+ print(f" {C.DIM}Prompt: {prompt}{C.RESET}\n")
174
+ start = time.time()
175
+ async for event in agent.query_stream(prompt, stream=True):
176
+ match event:
177
+ case TextChunkEvent(content=delta):
178
+ print(f"{C.YELLOW}{delta}{C.RESET}", end="", flush=True)
179
+ case TextEvent():
180
+ pass
181
+ case ToolCallEvent(tool=name, args=args):
182
+ print(f"\n {C.BLUE}>> Tool call: {name}({args}){C.RESET}")
183
+ case ToolResultEvent(tool=name, result=result):
184
+ preview = result[:150].replace("\n", "\\n")
185
+ print(f" {C.GREEN}<< {name}: {preview}...{C.RESET}")
186
+ case FinalResponseEvent():
187
+ elapsed = time.time() - start
188
+ print(f"\n {C.DIM}Completed in {elapsed:.2f}s{C.RESET}")
189
+
190
+
191
+ async def test_3_custom_tools():
192
+ """Test 3: Streaming with custom tools (calculator, get_time)."""
193
+ header("Test 3: Streaming with custom tools")
194
+ tools = [calculator, get_time]
195
+ prompt = "现在几点了?然后帮我算一下 (1234 + 5678) * 3 的结果。"
196
+
197
+ agent = Agent(llm=create_llm(), tools=tools)
198
+
199
+ print(f" {C.DIM}Prompt: {prompt}{C.RESET}\n")
200
+ async for event in agent.query_stream(prompt, stream=True):
201
+ match event:
202
+ case TextChunkEvent(content=delta):
203
+ print(f"{C.YELLOW}{delta}{C.RESET}", end="", flush=True)
204
+ case TextEvent():
205
+ pass
206
+ case ToolCallEvent(tool=name, args=args):
207
+ print(f"\n {C.BLUE}>> Tool call: {name}({args}){C.RESET}")
208
+ case ToolResultEvent(tool=name, result=result):
209
+ print(f" {C.GREEN}<< {name}: {result}{C.RESET}")
210
+ case FinalResponseEvent():
211
+ print()
212
+
213
+
214
+ async def test_4_multi_tool_workflow():
215
+ """Test 4: Complex workflow — write file, read it back, search content."""
216
+ header("Test 4: Multi-tool workflow (write → read → grep)")
217
+ workspace = str(Path(__file__).parent)
218
+ tools = [fs_write, fs_read, fs_grep, bash]
219
+
220
+ agent = Agent(
221
+ llm=create_llm(),
222
+ tools=tools,
223
+ sandbox=SandboxConfig(kind="local", work_dir=workspace),
224
+ )
225
+
226
+ prompt = (
227
+ "请完成以下任务:\n"
228
+ "1. 在当前目录创建一个文件 test_stream_data.txt,内容是 3 种编程语言的简介(每行一个)\n"
229
+ "2. 读取这个文件确认内容正确\n"
230
+ "3. 搜索文件中包含 Python 的行"
231
+ )
232
+
233
+ print(f" {C.DIM}Prompt: {prompt[:80]}...{C.RESET}\n")
234
+ tool_calls = 0
235
+ async for event in agent.query_stream(prompt, stream=True):
236
+ match event:
237
+ case TextChunkEvent(content=delta):
238
+ print(f"{C.YELLOW}{delta}{C.RESET}", end="", flush=True)
239
+ case TextEvent():
240
+ pass
241
+ case ToolCallEvent(tool=name, args=args):
242
+ tool_calls += 1
243
+ args_str = str(args)
244
+ if len(args_str) > 80:
245
+ args_str = args_str[:77] + "..."
246
+ print(f"\n {C.BLUE}[{tool_calls}] >> {name}({args_str}){C.RESET}")
247
+ case ToolResultEvent(tool=name, result=result):
248
+ preview = result[:120].replace("\n", "\\n")
249
+ print(f" {C.GREEN} << {name}: {preview}{C.RESET}")
250
+ case FinalResponseEvent():
251
+ print(f"\n {C.DIM}Total tool calls: {tool_calls}{C.RESET}")
252
+
253
+ # Cleanup
254
+ data_file = Path(workspace) / "test_stream_data.txt"
255
+ if data_file.exists():
256
+ data_file.unlink()
257
+ print(f" {C.DIM}Cleaned up test_stream_data.txt{C.RESET}")
258
+
259
+
260
+ async def test_5_skills():
261
+ """Test 5: Streaming with skills — create a skill and use it."""
262
+ header("Test 5: Streaming with skills")
263
+
264
+ # Create a temporary skills directory with a skill
265
+ workspace = str(Path(__file__).parent)
266
+ skills_dir = Path(workspace) / "_test_skills"
267
+ skills_dir.mkdir(exist_ok=True)
268
+
269
+ # Create a code-review skill
270
+ review_skill_dir = skills_dir / "code-review"
271
+ review_skill_dir.mkdir(exist_ok=True)
272
+ (review_skill_dir / "SKILL.md").write_text("""\
273
+ ---
274
+ name: code-review
275
+ description: Review code for bugs, security issues, and best practices
276
+ ---
277
+
278
+ # Code Review Skill
279
+
280
+ When reviewing code:
281
+ 1. Check for security vulnerabilities (SQL injection, XSS, etc.)
282
+ 2. Check for error handling issues
283
+ 3. Check for performance problems
284
+ 4. Check for code style and readability
285
+ 5. Provide specific suggestions for improvement
286
+ """)
287
+
288
+ # Create a git-commit skill
289
+ commit_skill_dir = skills_dir / "git-commit"
290
+ commit_skill_dir.mkdir(exist_ok=True)
291
+ (commit_skill_dir / "SKILL.md").write_text("""\
292
+ ---
293
+ name: git-commit
294
+ description: Generate conventional commit messages following project conventions
295
+ ---
296
+
297
+ # Git Commit Skill
298
+
299
+ Generate commit messages following the Conventional Commits specification:
300
+ - feat: New features
301
+ - fix: Bug fixes
302
+ - docs: Documentation changes
303
+ - refactor: Code refactoring
304
+ - test: Test additions/changes
305
+ - chore: Build/tooling changes
306
+ """)
307
+
308
+ tools = [bash, fs_read]
309
+ agent = Agent(
310
+ llm=create_llm(),
311
+ tools=tools,
312
+ skills_dir=str(skills_dir),
313
+ sandbox=SandboxConfig(kind="local", work_dir=str(Path(__file__).parent.parent)),
314
+ )
315
+
316
+ # Must call async_initialize to load skills
317
+ await agent.async_initialize()
318
+
319
+ print(f" {C.DIM}Loaded skills: {[s.name for s in agent._skills_manager.list()]}{C.RESET}")
320
+ print(f" {C.DIM}System prompt includes skills metadata: {'skills' in (agent.system_prompt or '').lower()}{C.RESET}\n")
321
+
322
+ prompt = "请列出所有可用的 skills,然后用 code-review skill 来审查以下代码的安全性: def query(user_input): return db.execute(f'SELECT * FROM users WHERE name={user_input}')"
323
+
324
+ async for event in agent.query_stream(prompt, stream=True):
325
+ match event:
326
+ case TextChunkEvent(content=delta):
327
+ print(f"{C.YELLOW}{delta}{C.RESET}", end="", flush=True)
328
+ case TextEvent():
329
+ pass
330
+ case ToolCallEvent(tool=name, args=args):
331
+ args_str = str(args)
332
+ if len(args_str) > 80:
333
+ args_str = args_str[:77] + "..."
334
+ print(f"\n {C.BLUE}>> {name}({args_str}){C.RESET}")
335
+ case ToolResultEvent(tool=name, result=result):
336
+ preview = result[:120].replace("\n", "\\n")
337
+ print(f" {C.GREEN} << {name}: {preview}{C.RESET}")
338
+ case FinalResponseEvent():
339
+ print()
340
+
341
+ # Cleanup
342
+ import shutil
343
+ if skills_dir.exists():
344
+ shutil.rmtree(skills_dir)
345
+ print(f" {C.DIM}Cleaned up _test_skills/{C.RESET}")
346
+
347
+
348
+ async def test_6_thinking_streaming():
349
+ """Test 6: Thinking content streaming (if model supports extended thinking)."""
350
+ header("Test 6: Thinking streaming")
351
+ tools = []
352
+ prompt = "9.11 和 9.8 哪个更大?请仔细思考后再回答。"
353
+
354
+ agent = Agent(llm=create_llm(thinking=True), tools=tools)
355
+
356
+ print(f" {C.DIM}Prompt: {prompt}{C.RESET}")
357
+ thinking_chunks = 0
358
+ text_chunks = 0
359
+ thinking_parts: list[str] = []
360
+ in_thinking = False
361
+ in_response = False
362
+
363
+ async for event in agent.query_stream(prompt, stream=True):
364
+ match event:
365
+ case ThinkingChunkEvent(content=delta):
366
+ thinking_chunks += 1
367
+ thinking_parts.append(delta)
368
+ if not in_thinking:
369
+ in_thinking = True
370
+ print(f"\n {C.BOLD}{C.MAGENTA}[Thinking]{C.RESET} ", end="", flush=True)
371
+ print(f"{C.MAGENTA}{delta}{C.RESET}", end="", flush=True)
372
+ case TextChunkEvent(content=delta):
373
+ if in_thinking:
374
+ in_thinking = False
375
+ print() # end thinking line
376
+ print(f"\n {C.BOLD}{C.YELLOW}[Response]{C.RESET} ", end="", flush=True)
377
+ in_response = True
378
+ text_chunks += 1
379
+ print(f"{C.YELLOW}{delta}{C.RESET}", end="", flush=True)
380
+ case TextEvent():
381
+ pass
382
+ case FinalResponseEvent():
383
+ if in_response or in_thinking:
384
+ print()
385
+ thinking_text = "".join(thinking_parts)
386
+ print(f"\n {C.DIM}{'─' * 50}{C.RESET}")
387
+ print(f" {C.BOLD}Stats:{C.RESET}")
388
+ print(f" Thinking: {C.MAGENTA}{thinking_chunks} chunks{C.RESET} ({len(thinking_text)} chars)")
389
+ print(f" Text: {C.YELLOW}{text_chunks} chunks{C.RESET}")
390
+ print(f" {C.DIM}{'─' * 50}{C.RESET}")
391
+
392
+
393
+ # ─── Main ───────────────────────────────────────────────────────────────────
394
+
395
+ TESTS = [
396
+ ("1", "Text-only streaming comparison", test_1_text_only_streaming),
397
+ ("2", "Built-in tools (bash, fs_glob, fs_read)", test_2_builtin_tools),
398
+ ("3", "Custom tools (calculator, get_time)", test_3_custom_tools),
399
+ ("4", "Multi-tool workflow (write→read→grep)", test_4_multi_tool_workflow),
400
+ ("5", "Skills (code-review, git-commit)", test_5_skills),
401
+ ("6", "Thinking streaming", test_6_thinking_streaming),
402
+ ]
403
+
404
+
405
+ async def run_all():
406
+ for _, desc, test_fn in TESTS:
407
+ try:
408
+ await test_fn()
409
+ except Exception as e:
410
+ print(f"\n {C.RED}FAILED: {e}{C.RESET}")
411
+ import traceback
412
+ traceback.print_exc()
413
+
414
+ print(f"\n{'=' * 70}")
415
+ print(f" {C.BOLD}{C.GREEN}All tests completed.{C.RESET}")
416
+ print(f"{'=' * 70}\n")
417
+
418
+
419
+ async def run_one(choice: str):
420
+ for key, desc, test_fn in TESTS:
421
+ if key == choice:
422
+ print(f"\n Running: {C.BOLD}{desc}{C.RESET}\n")
423
+ try:
424
+ await test_fn()
425
+ except Exception as e:
426
+ print(f"\n {C.RED}FAILED: {e}{C.RESET}")
427
+ import traceback
428
+ traceback.print_exc()
429
+ return
430
+ print(f" {C.RED}Unknown test: {choice}{C.RESET}")
431
+
432
+
433
+ if __name__ == "__main__":
434
+ print(f"\n{C.BOLD}zai-adk True Streaming Test Suite{C.RESET}")
435
+ print(f" Model: {os.getenv('OPENAI_MODEL', 'glm-4.7')}")
436
+ print(f" Base URL: {os.getenv('OPENAI_BASE_URL', '(default)')}")
437
+
438
+ if len(sys.argv) > 1:
439
+ choice = sys.argv[1]
440
+ if choice in ("all", "a"):
441
+ asyncio.run(run_all())
442
+ else:
443
+ asyncio.run(run_one(choice))
444
+ else:
445
+ print(f"\n Usage: python -m examples.test_streaming_real [test_number|all]")
446
+ print(f"\n Available tests:")
447
+ for key, desc, _ in TESTS:
448
+ print(f" {C.BOLD}{key}{C.RESET} {desc}")
449
+ print(f" {C.BOLD}all{C.RESET} Run all tests")
450
+ print()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zai-adk-python-preview"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  description = "A Python SDK for building AI agents with LLM integration"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"