diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-06-30 19:03:25 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-06-30 19:03:25 +0900 |
| commit | 05c8e0a31a0d4192c590e833b24393208e1c751f (patch) | |
| tree | f7c2c82c9327abde67bf3acf1d0258573b3bc6c2 /third_party/mcpc/src/ucbr.c | |
| parent | 4bc721c3bf7589b519c5730d093f704ce56e3f09 (diff) | |
fix: MCPCをvendored fork化しMCP準拠と接続安定性を改善
- Git submoduleを廃止してMCPCを直接管理
- Windowsで254リクエスト付近に発生する切断を修正
- JSON-RPC 2.0エラー応答を標準化
- tool schemaとruntimeの必須・任意引数を一致
- 1000回連続呼び出しの回帰テストを追加
Diffstat (limited to 'third_party/mcpc/src/ucbr.c')
| -rw-r--r-- | third_party/mcpc/src/ucbr.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/third_party/mcpc/src/ucbr.c b/third_party/mcpc/src/ucbr.c new file mode 100644 index 0000000..5dfce26 --- /dev/null +++ b/third_party/mcpc/src/ucbr.c @@ -0,0 +1,288 @@ +// This file is part of the mcpc library. +// +// Copyright (C) 2025 Michael Lee <micl2e2 AT proton.me> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "ucbr.h" + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> + +#include "alloc.h" +#include "anydata.h" +#include "errcode.h" +#include "ext_string.h" + +/* = = = = = = = = = = = = = = = = ucbrchd = = = = = = = = = = = = = = = = */ + +mcpc_ucbrchd_t * +mcpc_ucbrchd_new_vprintf8 (const char8_t *fmt, va_list *vargs) +{ + size_t sbuf_cap = 1024; + size_t sbuf_len = 0; + char8_t *sbuf = mcpc_alloc (sbuf_cap); + int printed = 0; + while (true) + { + va_list vargs_cp; + va_copy (vargs_cp, *vargs); + printed + = vsnprintf ((char *)sbuf, sbuf_cap, (const char *)fmt, vargs_cp); + bug_if (printed < 0); + if ((size_t)printed >= sbuf_cap) + { + sbuf_cap += sbuf_cap; + sbuf = mcpc_realloc (sbuf, sbuf_cap); + } + else + { + sbuf_len = (size_t)printed; + break; + } + } + + mcpc_anydata_t *anydata = mcpc_anydata_new_typ (MCPC_U8STR); + + if (MCPC_EC_0 != mcpc_anydata_set_u8str (anydata, sbuf, sbuf_len)) + goto badret; + + free (sbuf); + return (mcpc_ucbrchd_t *)anydata; + +badret: + free (sbuf); + mcpc_anydata_free (anydata); + return nullptr; +} + +mcpc_errcode_t +mcpc_ucbrchd_getref_u8str (const mcpc_ucbrchd_t *ucbrchd, const char8_t **ret, + size_t *ret_len) +{ + return mcpc_anydata_getref_u8str (ucbrchd, ret, ret_len); +} + +mcpc_errcode_t +mcpc_ucbrchd_get_data_type (const mcpc_ucbrchd_t *ucbrchd, mcpc_anytype_t *ret) +{ + bug_if_nullptr (ucbrchd); + bug_if_nullptr (ret); + + *ret = ucbrchd->data_typ; + + return MCPC_EC_0; +} + +bool +mcpc_ucbrchd_is_tool_callres (const mcpc_ucbrchd_t *ucbrchd) +{ + return ucbrchd->flags & ANYDATA_FL_USRCBRES_TOOLCALL; +} + +bool +mcpc_ucbrchd_is_prmpt_callres (const mcpc_ucbrchd_t *ucbrchd) +{ + return ucbrchd->flags & ANYDATA_FL_USRCBRES_PRMPTCALL; +} + +bool +mcpc_ucbrchd_is_assist_prmpt (const mcpc_ucbrchd_t *ucbrchd) +{ + return ucbrchd->flags & ANYDATA_FL_USRCBRES_PRMPTCALL_ASSIST; +} + +/* = = = = = = = = = = = = = = = = = ucbr = = = = = = = = = = = = = = = = = */ + +mcpc_ucbr_t * +mcpc_ucbr_new () +{ + return mcpc_anypool_new (); +} + +void +mcpc_ucbr_free (mcpc_ucbr_t *ucbr) +{ + mcpc_anypool_free (ucbr); +} + +void +mcpc_ucbr_addcpy (mcpc_ucbr_t *ucbr, const mcpc_ucbrchd_t *ucbrchd) +{ + mcpc_anypool_addcpy (ucbr, ucbrchd); +} + +void +mcpc_ucbr_addfre (mcpc_ucbr_t *ucbr, mcpc_ucbrchd_t *ucbrchd) +{ + mcpc_anypool_addfre (ucbr, ucbrchd); +} + +bool +mcpc_ucbr_is_err (const mcpc_ucbr_t *ucbr) +{ + bug_if_nullptr (ucbr); + return ucbr->flags & ANYPOOL_FL_USRCBRES_TOOLCALL_ERROR; +} + +size_t +mcpc_ucbr_get_len (const mcpc_ucbr_t *ucbr) +{ + bug_if_nullptr (ucbr); + size_t ret = 0; + ret = ((const mcpc_anypool_t *)ucbr)->len; + return ret; +} + +const mcpc_ucbrchd_t * +mcpc_ucbr_get (const mcpc_ucbr_t *ucbr, size_t idx) +{ + return mcpc_anypool_get (ucbr, idx); +} + +const mcpc_ucbrchd_t * +mcpc_ucbr_getbyname (const mcpc_ucbr_t *ucbr, const char8_t *name, + size_t name_len) +{ + return mcpc_anypool_getbymeta1 (ucbr, name, name_len); +} + +const mcpc_ucbrchd_t * +mcpc_ucbr_get_next (const mcpc_ucbr_t *ucbr) +{ + bug_if_nullptr (ucbr); + + static size_t idx = 0; + + const mcpc_anypool_t *pool = ucbr; + if (pool == nullptr) + return nullptr; + + const size_t pool_len = pool->len; + if (pool_len == 0) + return nullptr; + + if (idx == pool_len) // TODO MT-SAFE + { + idx = 0; + return nullptr; + } + + const mcpc_anydata_t *ret = pool->head + idx; + idx += 1; + + return ret; +} + +size_t +mcpc_ucbr_get_serlz_lenhint (const mcpc_ucbr_t *ucbr) +{ + bug_if_nullptr (ucbr); + size_t ret = 0; + + size_t length = mcpc_ucbr_get_len (ucbr); + for (size_t i = 0; i < length; ++i) + { + const mcpc_ucbrchd_t *cur_chd = mcpc_ucbr_get (ucbr, i); + ret += cur_chd->data_len; + } + + /* JSON string escaping can expand one input byte to six output bytes. */ + if (ret > (SIZE_MAX - 1024) / 6) + return 0; + ret = ret * 6 + 1024; + + return ret; +} + +void +mcpc_ucbr_toolcallres_add_text_vprintf8 (mcpc_ucbr_t *ucbr, const char8_t *fmt, + va_list *vargs) +{ + bug_if_nullptr (ucbr); + bug_if_nullptr (fmt); + bug_if_nullptr (vargs); + + ucbr->flags |= ANYPOOL_FL_USRCBRES_TOOLCALL; + + mcpc_ucbrchd_t *newctn = mcpc_ucbrchd_new_vprintf8 (fmt, vargs); + newctn->flags |= ANYDATA_FL_USRCBRES_TOOLCALL; + newctn->flags |= ANYDATA_FL_USRCBRES_TOOLCALL_TXTCTN; + mcpc_ucbr_addfre (ucbr, newctn); +} + +MCPC_API void +mcpc_ucbr_toolcall_add_text_printf8 (mcpc_ucbr_t *ucbr, const char8_t *fmt, + ...) +{ + va_list vargs; + va_start (vargs, fmt); + + mcpc_ucbr_toolcallres_add_text_vprintf8 (ucbr, fmt, &vargs); + + va_end (vargs); +} + +MCPC_API void +mcpc_ucbr_toolcall_add_errmsg_printf8 (mcpc_ucbr_t *ucbr, const char8_t *fmt, + ...) +{ + va_list vargs; + va_start (vargs, fmt); + + ucbr->flags |= ANYPOOL_FL_USRCBRES_TOOLCALL_ERROR; + mcpc_ucbr_toolcallres_add_text_vprintf8 (ucbr, fmt, &vargs); + + va_end (vargs); +} + +MCPC_API void +mcpc_ucbr_prmptget_add_user_printf8 (mcpc_ucbr_t *ucbr, const char8_t *fmt, + ...) +{ + va_list vargs; + va_start (vargs, fmt); + + ucbr->flags |= ANYPOOL_FL_USRCBRES_PRMPTCALL; + + mcpc_ucbrchd_t *newctn = mcpc_ucbrchd_new_vprintf8 (fmt, &vargs); + newctn->flags |= ANYDATA_FL_USRCBRES_PRMPTCALL; + + mcpc_ucbr_addfre (ucbr, newctn); + + va_end (vargs); +} + +MCPC_API void +mcpc_ucbr_prmptget_add_assist_printf8 (mcpc_ucbr_t *ucbr, const char8_t *fmt, + ...) +{ + va_list vargs; + va_start (vargs, fmt); + + ucbr->flags |= ANYPOOL_FL_USRCBRES_PRMPTCALL; + + mcpc_ucbrchd_t *newctn = mcpc_ucbrchd_new_vprintf8 (fmt, &vargs); + newctn->flags |= ANYDATA_FL_USRCBRES_PRMPTCALL; + newctn->flags |= ANYDATA_FL_USRCBRES_PRMPTCALL_ASSIST; + + mcpc_ucbr_addfre (ucbr, newctn); + + va_end (vargs); +} |
