aiexecode 1.0.73 → 1.0.75
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.
- package/package.json +1 -1
- package/payload_viewer/out/404/index.html +1 -1
- package/payload_viewer/out/404.html +1 -1
- package/payload_viewer/out/index.html +1 -1
- package/payload_viewer/out/index.txt +1 -1
- package/src/ai_based/completion_judge.js +20 -18
- package/src/ai_based/orchestrator.js +15 -159
- package/src/system/ai_request.js +199 -82
- package/src/system/conversation_trimmer.js +133 -0
- package/src/system/tool_approval.js +17 -6
- package/src/tools/code_editor.js +0 -2
- package/src/tools/file_reader.js +15 -14
- package/src/util/exit_handler.js +9 -0
- package/src/util/output_formatter.js +12 -19
- /package/payload_viewer/out/_next/static/{YeelNRX9W6c0YtiEzz_83 → jbur8fv1gX0ZHKro3t6lN}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{YeelNRX9W6c0YtiEzz_83 → jbur8fv1gX0ZHKro3t6lN}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{YeelNRX9W6c0YtiEzz_83 → jbur8fv1gX0ZHKro3t6lN}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--jbur8fv1gX0ZHKro3t6lN--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\n7:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nb:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\nc:\"$Sreact.suspense\"\ne:I[68027,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"jbur8fv1gX0ZHKro3t6lN\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$L6\",[\"$\",\"$L7\",null,{\"promise\":\"$@8\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$c\",null,{\"fallback\":null,\"children\":\"$Ld\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$e\",\"$undefined\"],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n6:null\n"])</script><script>self.__next_f.push([1,"f:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\n8:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$Lf\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"d:\"$8:metadata\"\n"])</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--jbur8fv1gX0ZHKro3t6lN--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\n7:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nb:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\nc:\"$Sreact.suspense\"\ne:I[68027,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"jbur8fv1gX0ZHKro3t6lN\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$L6\",[\"$\",\"$L7\",null,{\"promise\":\"$@8\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$c\",null,{\"fallback\":null,\"children\":\"$Ld\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$e\",\"$undefined\"],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n6:null\n"])</script><script>self.__next_f.push([1,"f:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\n8:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$Lf\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"d:\"$8:metadata\"\n"])</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--YeelNRX9W6c0YtiEzz_83--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><script src="/_next/static/chunks/f1ac9047ac4a3fde.js" async=""></script><script src="/_next/static/chunks/37d0cd2587a38f79.js" async=""></script><meta name="next-size-adjust" content=""/><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div class="h-screen bg-background flex"><div class="flex-shrink-0 w-80 border-r border-border bg-background flex flex-col"><div class="flex-shrink-0 border-b border-border p-4"><h2 class="text-lg font-semibold flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-5 w-5" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path><path d="M14 2v4a2 2 0 0 0 2 2h4"></path><path d="M10 9H8"></path><path d="M16 13H8"></path><path d="M16 17H8"></path></svg>로그 파일</h2><p class="text-sm text-muted-foreground">로딩 중...</p></div><div class="flex-1 min-h-0"><div dir="ltr" class="relative overflow-hidden h-full" style="position:relative;--radix-scroll-area-corner-width:0px;--radix-scroll-area-corner-height:0px"><style>[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}</style><div data-radix-scroll-area-viewport="" class="h-full w-full rounded-[inherit]" style="overflow-x:hidden;overflow-y:hidden"><div style="min-width:100%;display:table"><div class="p-4 text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-cw h-6 w-6 animate-spin mx-auto mb-2" aria-hidden="true"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path><path d="M8 16H3v5"></path></svg>로딩 중...</div></div></div></div></div></div><div class="flex-1 min-w-0"><div class="rounded-lg border bg-card text-card-foreground shadow-sm h-full"><div class="p-6 pt-0 flex items-center justify-center h-full"><div class="text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-pen h-12 w-12 mx-auto mb-4 opacity-50" aria-hidden="true"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"></path></svg><p class="text-lg">REQ 파일을 선택하세요</p><p class="text-sm">요청 파일을 선택하면 내용을 편집하고 재실행할 수 있습니다</p></div></div></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[47257,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ClientPageRoot\"]\n6:I[31713,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"/_next/static/chunks/37d0cd2587a38f79.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\nb:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\nd:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\n10:\"$Sreact.suspense\"\n12:I[68027,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"YeelNRX9W6c0YtiEzz_83\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L5\",null,{\"Component\":\"$6\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@7\",\"$@8\"]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/37d0cd2587a38f79.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$La\",[\"$\",\"$Lb\",null,{\"promise\":\"$@c\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$10\",null,{\"fallback\":null,\"children\":\"$L11\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$12\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"7:{}\n8:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\na:null\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\nc:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"11:\"$c:metadata\"\n"])</script></body></html>
|
|
1
|
+
<!DOCTYPE html><!--jbur8fv1gX0ZHKro3t6lN--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><script src="/_next/static/chunks/f1ac9047ac4a3fde.js" async=""></script><script src="/_next/static/chunks/37d0cd2587a38f79.js" async=""></script><meta name="next-size-adjust" content=""/><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div class="h-screen bg-background flex"><div class="flex-shrink-0 w-80 border-r border-border bg-background flex flex-col"><div class="flex-shrink-0 border-b border-border p-4"><h2 class="text-lg font-semibold flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-5 w-5" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path><path d="M14 2v4a2 2 0 0 0 2 2h4"></path><path d="M10 9H8"></path><path d="M16 13H8"></path><path d="M16 17H8"></path></svg>로그 파일</h2><p class="text-sm text-muted-foreground">로딩 중...</p></div><div class="flex-1 min-h-0"><div dir="ltr" class="relative overflow-hidden h-full" style="position:relative;--radix-scroll-area-corner-width:0px;--radix-scroll-area-corner-height:0px"><style>[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}</style><div data-radix-scroll-area-viewport="" class="h-full w-full rounded-[inherit]" style="overflow-x:hidden;overflow-y:hidden"><div style="min-width:100%;display:table"><div class="p-4 text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-cw h-6 w-6 animate-spin mx-auto mb-2" aria-hidden="true"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path><path d="M8 16H3v5"></path></svg>로딩 중...</div></div></div></div></div></div><div class="flex-1 min-w-0"><div class="rounded-lg border bg-card text-card-foreground shadow-sm h-full"><div class="p-6 pt-0 flex items-center justify-center h-full"><div class="text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-pen h-12 w-12 mx-auto mb-4 opacity-50" aria-hidden="true"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"></path></svg><p class="text-lg">REQ 파일을 선택하세요</p><p class="text-sm">요청 파일을 선택하면 내용을 편집하고 재실행할 수 있습니다</p></div></div></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[47257,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ClientPageRoot\"]\n6:I[31713,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"/_next/static/chunks/37d0cd2587a38f79.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\nb:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\nd:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\n10:\"$Sreact.suspense\"\n12:I[68027,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"jbur8fv1gX0ZHKro3t6lN\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L5\",null,{\"Component\":\"$6\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@7\",\"$@8\"]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/37d0cd2587a38f79.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$La\",[\"$\",\"$Lb\",null,{\"promise\":\"$@c\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$10\",null,{\"fallback\":null,\"children\":\"$L11\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$12\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"7:{}\n8:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\na:null\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\nc:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"11:\"$c:metadata\"\n"])</script></body></html>
|
|
@@ -13,7 +13,7 @@ f:I[97367,["/_next/static/chunks/060f9a97930f3d04.js"],"MetadataBoundary"]
|
|
|
13
13
|
:HL["/_next/static/chunks/ecd2072ebf41611f.css","style"]
|
|
14
14
|
:HL["/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
15
15
|
:HL["/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
16
|
-
0:{"P":null,"b":"
|
|
16
|
+
0:{"P":null,"b":"jbur8fv1gX0ZHKro3t6lN","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/ecd2072ebf41611f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/cdd12d5c1a5a6064.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"ko","className":"dark h-full","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L4",null,{"position":"bottom-right","toastOptions":{"duration":4000,"style":{"background":"hsl(var(--background))","color":"hsl(var(--foreground))","border":"1px solid hsl(var(--border))"}}}]]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L5",null,{"Component":"$6","searchParams":{},"params":{},"promises":["$@7","$@8"]}],[["$","script","script-0",{"src":"/_next/static/chunks/f1ac9047ac4a3fde.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/37d0cd2587a38f79.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$La",["$","$Lb",null,{"promise":"$@c"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Ld",null,{"children":"$Le"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$Lf",null,{"children":["$","div",null,{"hidden":true,"children":["$","$10",null,{"fallback":null,"children":"$L11"}]}]}]]}],false]],"m":"$undefined","G":["$12",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/ecd2072ebf41611f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"s":false,"S":true}
|
|
17
17
|
7:{}
|
|
18
18
|
8:"$0:f:0:1:2:children:1:props:children:0:props:params"
|
|
19
19
|
e:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import dotenv from "dotenv";
|
|
2
|
-
import { request,
|
|
2
|
+
import { request, shouldRetryWithTrim, getModelForProvider } from "../system/ai_request.js";
|
|
3
3
|
import { getOrchestratorConversation } from "./orchestrator.js";
|
|
4
4
|
import { createSystemMessage } from "../util/prompt_loader.js";
|
|
5
5
|
import { createDebugLogger } from "../util/debug_log.js";
|
|
6
6
|
import { getCurrentTodos } from "../system/session_memory.js";
|
|
7
|
+
import { cleanupOrphanOutputs, trimConversation } from "../system/conversation_trimmer.js";
|
|
7
8
|
|
|
8
9
|
dotenv.config({ quiet: true });
|
|
9
10
|
|
|
@@ -116,16 +117,7 @@ function syncOrchestratorConversation() {
|
|
|
116
117
|
debugLog(`[syncOrchestratorConversation] END`);
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
for (let i = 1; i < completionJudgeConversation.length - 1; i++) {
|
|
121
|
-
const candidate = completionJudgeConversation[i];
|
|
122
|
-
if (candidate?.role !== "system") {
|
|
123
|
-
completionJudgeConversation.splice(i, 1);
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
120
|
+
// 대화 cleanup 및 trim 함수는 conversation_trimmer 모듈에서 가져옴
|
|
129
121
|
|
|
130
122
|
async function dispatchCompletionJudgeRequest(options) {
|
|
131
123
|
debugLog(`[dispatchCompletionJudgeRequest] START`);
|
|
@@ -140,9 +132,10 @@ async function dispatchCompletionJudgeRequest(options) {
|
|
|
140
132
|
let attemptCount = 0;
|
|
141
133
|
while (true) {
|
|
142
134
|
attemptCount++;
|
|
143
|
-
debugLog(`[dispatchCompletionJudgeRequest] Attempt ${attemptCount}
|
|
135
|
+
debugLog(`[dispatchCompletionJudgeRequest] Attempt ${attemptCount} - starting cleanup...`);
|
|
136
|
+
cleanupOrphanOutputs(completionJudgeConversation);
|
|
144
137
|
|
|
145
|
-
|
|
138
|
+
debugLog(`[dispatchCompletionJudgeRequest] Conversation has ${completionJudgeConversation.length} entries`);
|
|
146
139
|
|
|
147
140
|
// Conversation 구조 분석
|
|
148
141
|
const conversationTypes = {};
|
|
@@ -151,7 +144,16 @@ async function dispatchCompletionJudgeRequest(options) {
|
|
|
151
144
|
conversationTypes[type] = (conversationTypes[type] || 0) + 1;
|
|
152
145
|
});
|
|
153
146
|
debugLog(`[dispatchCompletionJudgeRequest] Conversation structure: ${JSON.stringify(conversationTypes)}`);
|
|
154
|
-
|
|
147
|
+
|
|
148
|
+
// function_call_output 항목들 확인
|
|
149
|
+
const functionCallOutputs = completionJudgeConversation.filter(item => item.type === 'function_call_output');
|
|
150
|
+
debugLog(`[dispatchCompletionJudgeRequest] Found ${functionCallOutputs.length} function_call_output entries`);
|
|
151
|
+
|
|
152
|
+
functionCallOutputs.forEach((item, index) => {
|
|
153
|
+
debugLog(`[dispatchCompletionJudgeRequest] function_call_output[${index}] - call_id: ${item.call_id}, output length: ${item.output?.length || 0}, output preview: ${item.output?.substring(0, 200)}`);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const { model, isGpt5Model, taskName } = options;
|
|
155
157
|
|
|
156
158
|
const requestPayload = {
|
|
157
159
|
model,
|
|
@@ -197,13 +199,13 @@ async function dispatchCompletionJudgeRequest(options) {
|
|
|
197
199
|
throw error;
|
|
198
200
|
}
|
|
199
201
|
|
|
200
|
-
if (!
|
|
201
|
-
debugLog(`[dispatchCompletionJudgeRequest] Not
|
|
202
|
+
if (!shouldRetryWithTrim(error)) {
|
|
203
|
+
debugLog(`[dispatchCompletionJudgeRequest] Not recoverable by trimming, re-throwing`);
|
|
202
204
|
throw error;
|
|
203
205
|
}
|
|
204
206
|
|
|
205
|
-
debugLog(`[dispatchCompletionJudgeRequest]
|
|
206
|
-
const trimmed =
|
|
207
|
+
debugLog(`[dispatchCompletionJudgeRequest] Recoverable error detected, attempting to trim...`);
|
|
208
|
+
const trimmed = trimConversation(completionJudgeConversation);
|
|
207
209
|
debugLog(`[dispatchCompletionJudgeRequest] Trim result: ${trimmed}, new conversation length: ${completionJudgeConversation.length}`);
|
|
208
210
|
if (!trimmed) {
|
|
209
211
|
debugLog(`[dispatchCompletionJudgeRequest] Cannot trim further, re-throwing error`);
|
|
@@ -3,7 +3,8 @@ import dotenv from "dotenv";
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { truncateWithOmit } from "../util/text_formatter.js";
|
|
5
5
|
import { createSystemMessage } from "../util/prompt_loader.js";
|
|
6
|
-
import { request,
|
|
6
|
+
import { request, shouldRetryWithTrim, getModelForProvider } from "../system/ai_request.js";
|
|
7
|
+
import { cleanupOrphanOutputs, trimConversation } from "../system/conversation_trimmer.js";
|
|
7
8
|
import { runPythonCodeSchema, bashSchema } from "../system/code_executer.js";
|
|
8
9
|
import { readFileSchema, readFileRangeSchema } from "../tools/file_reader.js";
|
|
9
10
|
import { writeFileSchema, editFileRangeSchema, editFileReplaceSchema } from "../tools/code_editor.js";
|
|
@@ -120,18 +121,6 @@ export function recordOrchestratorToolResult({ toolCallId, toolName = '', argume
|
|
|
120
121
|
return null;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
if (toolName === 'read_file') {
|
|
124
|
-
const filePath = toolArguments.filePath || '';
|
|
125
|
-
const absolutePath = path.isAbsolute(filePath)
|
|
126
|
-
? filePath
|
|
127
|
-
: path.join(process.cwd(), filePath);
|
|
128
|
-
|
|
129
|
-
stdout = JSON.stringify({
|
|
130
|
-
absolute_file_path: absolutePath,
|
|
131
|
-
content: stdout
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
124
|
const payload = {
|
|
136
125
|
tool: toolName || null,
|
|
137
126
|
call_id: toolCallId,
|
|
@@ -154,146 +143,7 @@ export function recordOrchestratorToolResult({ toolCallId, toolName = '', argume
|
|
|
154
143
|
return toolResult;
|
|
155
144
|
}
|
|
156
145
|
|
|
157
|
-
|
|
158
|
-
if (!item || typeof item !== 'object') {
|
|
159
|
-
return [];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const callIds = new Set();
|
|
163
|
-
|
|
164
|
-
const maybeIds = [item.call_id, item.tool_call_id, item.id];
|
|
165
|
-
for (const id of maybeIds) {
|
|
166
|
-
if (typeof id === 'string' && id.trim().length) {
|
|
167
|
-
callIds.add(id);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (item.function && typeof item.function === 'object') {
|
|
172
|
-
const fnIds = [item.function.call_id, item.function.id];
|
|
173
|
-
for (const id of fnIds) {
|
|
174
|
-
if (typeof id === 'string' && id.trim().length) {
|
|
175
|
-
callIds.add(id);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (Array.isArray(item.tool_calls)) {
|
|
181
|
-
for (const toolCall of item.tool_calls) {
|
|
182
|
-
extractCallIdsFromItem(toolCall).forEach(id => callIds.add(id));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return Array.from(callIds);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function removeConversationEntriesByCallIds(callIds) {
|
|
190
|
-
if (!Array.isArray(callIds) || callIds.length === 0) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const callIdSet = new Set(callIds.filter(id => typeof id === 'string' && id.trim().length));
|
|
195
|
-
if (!callIdSet.size) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
for (let index = orchestratorConversation.length - 1; index >= 0; index--) {
|
|
200
|
-
const entry = orchestratorConversation[index];
|
|
201
|
-
if (!entry || typeof entry !== 'object') {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (entry.type === 'function_call_output') {
|
|
206
|
-
if (callIdSet.has(entry.call_id)) {
|
|
207
|
-
orchestratorConversation.splice(index, 1);
|
|
208
|
-
}
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (Array.isArray(entry.tool_calls) && entry.tool_calls.length) {
|
|
213
|
-
const filteredToolCalls = entry.tool_calls.filter(toolCall => {
|
|
214
|
-
const ids = extractCallIdsFromItem(toolCall);
|
|
215
|
-
return !ids.some(id => callIdSet.has(id));
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
if (filteredToolCalls.length !== entry.tool_calls.length) {
|
|
219
|
-
if (filteredToolCalls.length === 0 && (!entry.content || entry.content.length === 0)) {
|
|
220
|
-
orchestratorConversation.splice(index, 1);
|
|
221
|
-
} else {
|
|
222
|
-
entry.tool_calls = filteredToolCalls;
|
|
223
|
-
}
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const entryCallIds = extractCallIdsFromItem(entry);
|
|
229
|
-
if (entryCallIds.some(id => callIdSet.has(id))) {
|
|
230
|
-
orchestratorConversation.splice(index, 1);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function cleanupOrchestratorConversation() {
|
|
236
|
-
debugLog(`[cleanupOrchestratorConversation] Starting cleanup, conversation length: ${orchestratorConversation.length}`);
|
|
237
|
-
|
|
238
|
-
const validCallIds = new Set();
|
|
239
|
-
|
|
240
|
-
for (const entry of orchestratorConversation) {
|
|
241
|
-
if (!entry || typeof entry !== 'object') {
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (entry.type === 'function_call') {
|
|
246
|
-
const ids = extractCallIdsFromItem(entry);
|
|
247
|
-
debugLog(`[cleanupOrchestratorConversation] Found function_call with call_ids: ${ids.join(', ')}`);
|
|
248
|
-
ids.forEach(id => validCallIds.add(id));
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (Array.isArray(entry.tool_calls)) {
|
|
252
|
-
for (const toolCall of entry.tool_calls) {
|
|
253
|
-
const ids = extractCallIdsFromItem(toolCall);
|
|
254
|
-
debugLog(`[cleanupOrchestratorConversation] Found tool_call with call_ids: ${ids.join(', ')}`);
|
|
255
|
-
ids.forEach(id => validCallIds.add(id));
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
debugLog(`[cleanupOrchestratorConversation] Valid call IDs: ${Array.from(validCallIds).join(', ')}`);
|
|
261
|
-
|
|
262
|
-
for (let index = orchestratorConversation.length - 1; index >= 0; index--) {
|
|
263
|
-
const entry = orchestratorConversation[index];
|
|
264
|
-
if (entry?.type === 'function_call_output') {
|
|
265
|
-
const callId = entry.call_id;
|
|
266
|
-
if (!callId || !validCallIds.has(callId)) {
|
|
267
|
-
debugLog(`[cleanupOrchestratorConversation] REMOVING function_call_output at index ${index} with call_id: ${callId} (not in validCallIds)`);
|
|
268
|
-
orchestratorConversation.splice(index, 1);
|
|
269
|
-
} else {
|
|
270
|
-
debugLog(`[cleanupOrchestratorConversation] KEEPING function_call_output at index ${index} with call_id: ${callId}, output length: ${entry.output?.length || 0}`);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
debugLog(`[cleanupOrchestratorConversation] Finished cleanup, conversation length: ${orchestratorConversation.length}`);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function trimOrchestratorConversation() {
|
|
279
|
-
if (orchestratorConversation.length <= 2) {
|
|
280
|
-
return false;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
for (let i = 1; i < orchestratorConversation.length - 1; i++) {
|
|
284
|
-
const target = orchestratorConversation[i];
|
|
285
|
-
const callIds = extractCallIdsFromItem(target);
|
|
286
|
-
|
|
287
|
-
orchestratorConversation.splice(i, 1);
|
|
288
|
-
|
|
289
|
-
if (callIds.length) {
|
|
290
|
-
removeConversationEntriesByCallIds(callIds);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return true;
|
|
294
|
-
}
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
146
|
+
// 대화 cleanup 및 trim 함수는 conversation_trimmer 모듈에서 가져옴
|
|
297
147
|
|
|
298
148
|
async function dispatchOrchestratorRequest({ toolChoice }) {
|
|
299
149
|
debugLog(`[dispatchOrchestratorRequest] START - toolChoice: ${toolChoice}`);
|
|
@@ -309,7 +159,7 @@ async function dispatchOrchestratorRequest({ toolChoice }) {
|
|
|
309
159
|
while (true) {
|
|
310
160
|
attemptCount++;
|
|
311
161
|
debugLog(`[dispatchOrchestratorRequest] Attempt ${attemptCount} - starting cleanup...`);
|
|
312
|
-
|
|
162
|
+
cleanupOrphanOutputs(orchestratorConversation);
|
|
313
163
|
|
|
314
164
|
debugLog(`[dispatchOrchestratorRequest] Conversation has ${orchestratorConversation.length} entries`);
|
|
315
165
|
|
|
@@ -370,15 +220,21 @@ async function dispatchOrchestratorRequest({ toolChoice }) {
|
|
|
370
220
|
return response;
|
|
371
221
|
} catch (error) {
|
|
372
222
|
debugLog(`[dispatchOrchestratorRequest] API request failed: ${error.message}`);
|
|
373
|
-
debugLog(`[dispatchOrchestratorRequest] Error
|
|
223
|
+
debugLog(`[dispatchOrchestratorRequest] Error name: ${error.name}, type: ${error?.constructor?.name}`);
|
|
224
|
+
|
|
225
|
+
// AbortError는 즉시 전파 (세션 중단)
|
|
226
|
+
if (error.name === 'AbortError') {
|
|
227
|
+
debugLog(`[dispatchOrchestratorRequest] Request aborted by user, propagating AbortError`);
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
374
230
|
|
|
375
|
-
if (!
|
|
376
|
-
debugLog(`[dispatchOrchestratorRequest] Not
|
|
231
|
+
if (!shouldRetryWithTrim(error)) {
|
|
232
|
+
debugLog(`[dispatchOrchestratorRequest] Not recoverable by trimming, re-throwing`);
|
|
377
233
|
throw error;
|
|
378
234
|
}
|
|
379
235
|
|
|
380
|
-
debugLog(`[dispatchOrchestratorRequest]
|
|
381
|
-
const trimmed =
|
|
236
|
+
debugLog(`[dispatchOrchestratorRequest] Recoverable error detected, attempting to trim conversation...`);
|
|
237
|
+
const trimmed = trimConversation(orchestratorConversation);
|
|
382
238
|
debugLog(`[dispatchOrchestratorRequest] Trim result: ${trimmed}, new conversation length: ${orchestratorConversation.length}`);
|
|
383
239
|
if (!trimmed) {
|
|
384
240
|
debugLog(`[dispatchOrchestratorRequest] Cannot trim further, re-throwing error`);
|
package/src/system/ai_request.js
CHANGED
|
@@ -193,10 +193,49 @@ export async function request(taskName, requestPayload) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
debugLog(`[request] Starting payload transformation...`);
|
|
196
|
+
const isValidJSON = (json) => {
|
|
197
|
+
if (typeof json !== 'string') return false;
|
|
198
|
+
try {
|
|
199
|
+
JSON.parse(json);
|
|
200
|
+
return true;
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (true && payloadCopy.input && Array.isArray(payloadCopy.input)) {
|
|
206
|
+
for (let i = payloadCopy.input.length - 1; i >= 0; i--) {
|
|
207
|
+
const msg = payloadCopy.input[i];
|
|
208
|
+
const { type, call_id, output } = msg;
|
|
209
|
+
if (type !== 'function_call_output') continue;
|
|
210
|
+
const parsedOutput = JSON.parse(output);
|
|
211
|
+
if (!isValidJSON(parsedOutput.stdout)) {
|
|
212
|
+
// stdout와 stderr를 모두 포함하는 형식으로 변환
|
|
213
|
+
const hasStdout = parsedOutput.stdout;
|
|
214
|
+
const hasStderr = parsedOutput.stderr;
|
|
215
|
+
|
|
216
|
+
if (hasStdout && hasStderr) {
|
|
217
|
+
// 둘 다 있으면 레이블 포함
|
|
218
|
+
msg.output = `stdout:\n${parsedOutput.stdout}\n\nstderr:\n${parsedOutput.stderr}`;
|
|
219
|
+
} else if (hasStderr) {
|
|
220
|
+
// stderr만 있으면 레이블 포함
|
|
221
|
+
msg.output = `stderr:\n${parsedOutput.stderr}`;
|
|
222
|
+
} else {
|
|
223
|
+
// stdout만 있으면 레이블 없이
|
|
224
|
+
msg.output = parsedOutput.stdout;
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
parsedOutput.stdout = JSON.parse(parsedOutput.stdout);
|
|
228
|
+
if (parsedOutput.original_result) {
|
|
229
|
+
parsedOutput.stdout = ({ ...parsedOutput.original_result, ...(parsedOutput.stdout) });
|
|
230
|
+
delete parsedOutput.original_result;
|
|
231
|
+
}
|
|
232
|
+
msg.output = parsedOutput;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
196
236
|
if (payloadCopy.input && Array.isArray(payloadCopy.input)) {
|
|
197
237
|
const marker = {};
|
|
198
238
|
const remove_call_id = {};//[];
|
|
199
|
-
const response_message_call_id = {};
|
|
200
239
|
|
|
201
240
|
debugLog(`[request] Processing ${payloadCopy.input.length} input messages for deduplication and formatting`);
|
|
202
241
|
let processedCount = 0;
|
|
@@ -207,105 +246,182 @@ export async function request(taskName, requestPayload) {
|
|
|
207
246
|
if (type !== 'function_call_output') continue;
|
|
208
247
|
processedCount++;
|
|
209
248
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const parsedOutput = JSON.parse(output);
|
|
213
|
-
const { tool, stdout, stderr, exit_code } = parsedOutput;
|
|
214
|
-
|
|
215
|
-
debugLog(`[ai_request] Parsed output - tool: ${tool}, stdout: ${stdout?.length || 0} bytes, stderr: ${stderr?.length || 0} bytes`);
|
|
249
|
+
if ((typeof output) === 'string') continue;
|
|
250
|
+
const { tool, stdout, stderr, exit_code, original_result } = output;
|
|
216
251
|
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
delete parsedStdout.file_stats;
|
|
224
|
-
if (marker[abolute_path]) {
|
|
225
|
-
parsedStdout.target_file_path;
|
|
226
|
-
} else {
|
|
227
|
-
if (updated_content) {
|
|
228
|
-
parsedStdout.updated_content = formatReadFileStdout({ file_lines: updated_content.split('\n') });
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
marker[abolute_path] = true;
|
|
232
|
-
msg.output = JSON.stringify(parsedStdout, null, 2);
|
|
233
|
-
debugLog(`[ai_request] edit_file_range - new output length: ${msg.output.length}`);
|
|
234
|
-
}
|
|
235
|
-
else if (tool === 'edit_file_replace') {
|
|
236
|
-
const parsedStdout = JSON.parse(stdout);
|
|
237
|
-
if (!parsedStdout.absolute_file_path) continue;
|
|
238
|
-
let abolute_path = toAbsolutePath(parsedStdout.absolute_file_path)
|
|
239
|
-
const updated_content = parsedStdout.file_stats?.updated_content;
|
|
240
|
-
delete parsedStdout.absolute_file_path;
|
|
241
|
-
delete parsedStdout.file_stats;
|
|
242
|
-
if (marker[abolute_path]) {
|
|
243
|
-
parsedStdout.target_file_path;
|
|
244
|
-
} else {
|
|
245
|
-
if (updated_content) {
|
|
246
|
-
parsedStdout.updated_content = formatReadFileStdout({ file_lines: updated_content.split('\n') });
|
|
247
|
-
}
|
|
248
|
-
}
|
|
252
|
+
if (stdout?.operation_successful?.constructor === Boolean && !stdout.operation_successful) continue;
|
|
253
|
+
if (tool === 'edit_file_range' || tool === 'edit_file_replace') {
|
|
254
|
+
let abolute_path = toAbsolutePath(stdout.target_file_path);
|
|
255
|
+
const updated_content = stdout.file_stats?.updated_content;
|
|
256
|
+
delete stdout.file_stats;
|
|
257
|
+
if (!marker[abolute_path] && updated_content) stdout.updated_content = updated_content.split('\n');
|
|
249
258
|
marker[abolute_path] = true;
|
|
250
|
-
msg.output = JSON.stringify(parsedStdout, null, 2);
|
|
251
|
-
debugLog(`[ai_request] edit_file_replace - new output length: ${msg.output.length}`);
|
|
252
259
|
}
|
|
253
260
|
else if (tool === 'read_file') {
|
|
254
|
-
|
|
255
|
-
if (!parsedStdout.absolute_file_path) continue;
|
|
256
|
-
let abolute_path = toAbsolutePath(parsedStdout.absolute_file_path)
|
|
257
|
-
const content = parsedStdout.content;
|
|
261
|
+
let abolute_path = toAbsolutePath(stdout.target_file_path);
|
|
258
262
|
if (marker[abolute_path]) {
|
|
259
|
-
remove_call_id[call_id] = true
|
|
260
|
-
|
|
261
|
-
} else {
|
|
262
|
-
msg.output = content;
|
|
263
|
+
remove_call_id[call_id] = true;
|
|
264
|
+
stdout.file_content = '(Not displayed)';
|
|
263
265
|
}
|
|
264
266
|
marker[abolute_path] = true;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
msg.output
|
|
279
|
-
debugLog(`[ai_request] OTHER TOOL (${tool}) - AFTER: output length: ${msg.output.length} bytes (stdout: ${stdout?.length || 0}, stderr: ${stderr?.length || 0})`);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// debugLog(`[ai_request] OTHER TOOL (${tool}) - BEFORE: output is full JSON with stderr`);
|
|
270
|
+
// // run_python_code, bash 등의 경우 stdout과 stderr를 모두 포함
|
|
271
|
+
// let combinedOutput = '';
|
|
272
|
+
// if (stdout && stderr) {
|
|
273
|
+
// combinedOutput = `stdout:\n${stdout}\n\nstderr:\n${stderr}`;
|
|
274
|
+
// } else if (stdout) {
|
|
275
|
+
// combinedOutput = stdout;
|
|
276
|
+
// } else if (stderr) {
|
|
277
|
+
// combinedOutput = `stderr:\n${stderr}`;
|
|
278
|
+
// }
|
|
279
|
+
// msg.output = combinedOutput;
|
|
280
|
+
// debugLog(`[ai_request] OTHER TOOL (${tool}) - AFTER: output length: ${msg.output.length} bytes (stdout: ${stdout?.length || 0}, stderr: ${stderr?.length || 0})`);
|
|
280
281
|
}
|
|
281
282
|
}
|
|
282
283
|
|
|
283
284
|
debugLog(`[request] Processed ${processedCount} function_call_output entries`);
|
|
284
285
|
debugLog(`[request] Marked files for deduplication: ${Object.keys(marker).length}`);
|
|
285
286
|
|
|
286
|
-
|
|
287
|
+
}
|
|
288
|
+
if (true && payloadCopy.input && Array.isArray(payloadCopy.input)) {
|
|
289
|
+
const response_message_call_id = {};
|
|
287
290
|
for (let i = payloadCopy.input.length - 1; i >= 0; i--) {
|
|
288
291
|
const msg = payloadCopy.input[i];
|
|
289
292
|
const { type, call_id, name } = msg;
|
|
290
293
|
if (type !== 'function_call') continue;
|
|
291
294
|
if (name !== 'response_message') continue;
|
|
292
295
|
response_message_call_id[call_id] = true;
|
|
293
|
-
responseMessageCount++;
|
|
294
296
|
}
|
|
295
|
-
debugLog(`[request] Found ${responseMessageCount} response_message function calls`);
|
|
296
|
-
|
|
297
|
-
let simplifiedResponseMessages = 0;
|
|
298
297
|
for (let i = payloadCopy.input.length - 1; i >= 0; i--) {
|
|
299
298
|
const msg = payloadCopy.input[i];
|
|
300
299
|
const { type, call_id } = msg;
|
|
301
300
|
if (type !== 'function_call_output') continue;
|
|
302
301
|
if (!response_message_call_id[call_id]) continue;
|
|
303
|
-
msg.output =
|
|
304
|
-
|
|
302
|
+
msg.output = {
|
|
303
|
+
tool: 'response_message',
|
|
304
|
+
stdout: { message_displayed: true }
|
|
305
|
+
};
|
|
305
306
|
}
|
|
306
|
-
debugLog(`[request] Simplified ${simplifiedResponseMessages} response_message outputs`);
|
|
307
307
|
}
|
|
308
|
+
// Formatting
|
|
309
|
+
if (true && payloadCopy.input && Array.isArray(payloadCopy.input)) {
|
|
310
|
+
for (let i = payloadCopy.input.length - 1; i >= 0; i--) {
|
|
311
|
+
const msg = payloadCopy.input[i];
|
|
312
|
+
const { type, call_id, output } = msg;
|
|
313
|
+
|
|
314
|
+
if (type !== 'function_call_output') continue;
|
|
315
|
+
if (typeof output === 'string') continue;
|
|
316
|
+
const { tool, stdout, stderr, exit_code, original_result } = output;
|
|
317
|
+
if (false) await safeWriteFile('./__stdout/' + tool + '.' + (call_id) + '.json', JSON.stringify(stdout, null, 2));
|
|
318
|
+
|
|
319
|
+
// read_file
|
|
320
|
+
if (tool === 'read_file') {
|
|
321
|
+
if (!stdout.operation_successful) {
|
|
322
|
+
msg.output = stdout.error_message;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
if (stdout.file_content.includes('\n')) {
|
|
326
|
+
msg.output = formatReadFileStdout(stdout.file_content);
|
|
327
|
+
} else {
|
|
328
|
+
msg.output = (stdout.file_content);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// read_file_range
|
|
335
|
+
if (tool === 'read_file_range') {
|
|
336
|
+
if (!stdout.operation_successful) {
|
|
337
|
+
msg.output = stdout.error_message;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
msg.output = formatReadFileStdout(stdout.file_content, stdout.actual_range.start_line);
|
|
341
|
+
}
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// write_file
|
|
346
|
+
if (tool === 'write_file') {
|
|
347
|
+
if (!stdout.operation_successful) {
|
|
348
|
+
msg.output = stdout.error_message;
|
|
349
|
+
} else {
|
|
350
|
+
msg.output = `File written successfully: ${stdout.target_file_path}`;
|
|
351
|
+
}
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// edit_file_replace
|
|
356
|
+
if (tool === 'edit_file_replace') {
|
|
357
|
+
if (!stdout.operation_successful) {
|
|
358
|
+
msg.output = stdout.error_message;
|
|
359
|
+
} else {
|
|
360
|
+
// const isString = stdout?.updated_content?.constructor === String;
|
|
361
|
+
const newObj = {
|
|
362
|
+
unified_diff_patch: stdout.diff_info.unified_diff_patch,
|
|
363
|
+
operation_successful: stdout.operation_successful,
|
|
364
|
+
updated_content: formatReadFileStdout(stdout?.updated_content?.join('\n')),
|
|
365
|
+
};
|
|
366
|
+
if (!(stdout?.updated_content)) delete newObj.updated_content;
|
|
367
|
+
// if (!isString) delete newObj.updated_content;
|
|
368
|
+
msg.output = JSON.stringify(newObj, null, 2);
|
|
369
|
+
}
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
308
372
|
|
|
373
|
+
// edit_file_range
|
|
374
|
+
if (tool === 'edit_file_range') {
|
|
375
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ripgrep
|
|
380
|
+
if (tool === 'ripgrep') {
|
|
381
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// glob_search
|
|
386
|
+
if (tool === 'glob_search') {
|
|
387
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// fetch_web_page
|
|
392
|
+
if (tool === 'fetch_web_page') {
|
|
393
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// response_message
|
|
398
|
+
if (tool === 'response_message') {
|
|
399
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// todo_write
|
|
404
|
+
if (tool === 'todo_write') {
|
|
405
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// bash (from code_executer.js)
|
|
410
|
+
if (tool === 'bash') {
|
|
411
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// run_python_code (from code_executer.js)
|
|
416
|
+
if (tool === 'run_python_code') {
|
|
417
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Default case for unknown tools
|
|
422
|
+
msg.output = JSON.stringify(stdout, null, 2);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
309
425
|
debugLog(`[request] Payload transformation complete`);
|
|
310
426
|
let response;
|
|
311
427
|
let originalRequest;
|
|
@@ -424,37 +540,38 @@ export async function request(taskName, requestPayload) {
|
|
|
424
540
|
}
|
|
425
541
|
|
|
426
542
|
/**
|
|
427
|
-
*
|
|
543
|
+
* API 에러가 대화 trim 후 재시도로 복구 가능한지 확인합니다.
|
|
428
544
|
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
545
|
+
* 처리 대상:
|
|
546
|
+
* - context_length_exceeded: 컨텍스트 윈도우 초과
|
|
547
|
+
* - 400 error: 잘못된 요청 (대화가 너무 길어서 발생 가능)
|
|
431
548
|
*
|
|
432
549
|
* @param {Error | Object} error - 확인할 에러 객체
|
|
433
|
-
* @returns {boolean}
|
|
550
|
+
* @returns {boolean} trim 후 재시도 가능 여부
|
|
434
551
|
*
|
|
435
552
|
* @see https://platform.openai.com/docs/guides/error-codes
|
|
436
553
|
*/
|
|
437
|
-
export function
|
|
554
|
+
export function shouldRetryWithTrim(error) {
|
|
438
555
|
if (!error) return false;
|
|
439
556
|
|
|
440
557
|
// OpenAI SDK의 공식 에러 코드 확인
|
|
441
|
-
// error.code 또는 error.error.code에서 확인
|
|
442
558
|
const errorCode = error?.code || error?.error?.code;
|
|
443
559
|
|
|
444
560
|
if (errorCode === 'context_length_exceeded') {
|
|
445
|
-
debugLog('[
|
|
561
|
+
debugLog('[shouldRetryWithTrim] Detected: context_length_exceeded');
|
|
446
562
|
return true;
|
|
447
563
|
}
|
|
448
564
|
|
|
449
|
-
//
|
|
565
|
+
// 400 에러도 trim 후 재시도 대상
|
|
450
566
|
if (error?.status === 400 || error?.response?.status === 400) {
|
|
451
567
|
const errorType = error?.type || error?.error?.type;
|
|
452
568
|
const errorMessage = error?.message || error?.error?.message || '';
|
|
453
569
|
debugLog(
|
|
454
|
-
`[
|
|
455
|
-
`
|
|
570
|
+
`[shouldRetryWithTrim] Detected 400 error - ` +
|
|
571
|
+
`Type: ${errorType}, Code: ${errorCode}, ` +
|
|
456
572
|
`Message: ${errorMessage.substring(0, 200)}`
|
|
457
573
|
);
|
|
574
|
+
return true;
|
|
458
575
|
}
|
|
459
576
|
|
|
460
577
|
return false;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 대화 히스토리 trim 및 정리 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* orchestrator와 completion_judge에서 공통으로 사용하는
|
|
5
|
+
* 대화 관리 기능을 중앙집중화합니다.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createDebugLogger } from "../util/debug_log.js";
|
|
9
|
+
|
|
10
|
+
const debugLog = createDebugLogger('conversation_trimmer.log', 'conversation_trimmer');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 대화에서 특정 call_id와 관련된 모든 항목을 제거합니다.
|
|
14
|
+
*
|
|
15
|
+
* @param {Array} conversation - 대화 배열
|
|
16
|
+
* @param {string} callIdToRemove - 제거할 call_id
|
|
17
|
+
*/
|
|
18
|
+
export function removeEntriesWithCallId(conversation, callIdToRemove) {
|
|
19
|
+
if (!callIdToRemove || typeof callIdToRemove !== 'string') {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
debugLog(`[removeEntriesWithCallId] Looking for entries with call_id: ${callIdToRemove}`);
|
|
24
|
+
|
|
25
|
+
// 1단계: 삭제할 항목들의 인덱스를 먼저 수집 (반복 중에는 배열 수정 금지)
|
|
26
|
+
const indicesToRemove = [];
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < conversation.length; i++) {
|
|
29
|
+
const entry = conversation[i];
|
|
30
|
+
|
|
31
|
+
// call_id 속성이 있고 값이 일치하면 삭제 목록에 추가
|
|
32
|
+
if (entry && entry.call_id === callIdToRemove) {
|
|
33
|
+
indicesToRemove.push(i);
|
|
34
|
+
debugLog(`[removeEntriesWithCallId] Marked index ${i} for removal (type: ${entry.type})`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2단계: 수집된 인덱스를 역순으로 삭제 (뒤에서부터 지워야 인덱스가 꼬이지 않음)
|
|
39
|
+
for (let i = indicesToRemove.length - 1; i >= 0; i--) {
|
|
40
|
+
const indexToRemove = indicesToRemove[i];
|
|
41
|
+
conversation.splice(indexToRemove, 1);
|
|
42
|
+
debugLog(`[removeEntriesWithCallId] Removed entry at index ${indexToRemove}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
debugLog(`[removeEntriesWithCallId] Total removed: ${indicesToRemove.length} entries`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 고아(orphan) function_call_output을 제거합니다.
|
|
50
|
+
*
|
|
51
|
+
* 고아 output이란?
|
|
52
|
+
* - function_call은 없는데 function_call_output만 남아있는 경우
|
|
53
|
+
* - 예: function_call을 trim했는데 output은 뒤에 남아있는 경우
|
|
54
|
+
*
|
|
55
|
+
* @param {Array} conversation - 대화 배열
|
|
56
|
+
*/
|
|
57
|
+
export function cleanupOrphanOutputs(conversation) {
|
|
58
|
+
debugLog(`[cleanupOrphanOutputs] Starting cleanup, conversation length: ${conversation.length}`);
|
|
59
|
+
|
|
60
|
+
// 1단계: "어떤 function_call들이 대화에 있는가?" 파악
|
|
61
|
+
const existingCallIds = new Set();
|
|
62
|
+
|
|
63
|
+
for (const entry of conversation) {
|
|
64
|
+
if (entry?.type === 'function_call' && entry.call_id) {
|
|
65
|
+
existingCallIds.add(entry.call_id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
debugLog(`[cleanupOrphanOutputs] Found ${existingCallIds.size} function_calls`);
|
|
70
|
+
|
|
71
|
+
// 2단계: "고아 output 찾기" - call_id가 없거나, 대응하는 function_call이 없는 output
|
|
72
|
+
const orphanIndexes = [];
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < conversation.length; i++) {
|
|
75
|
+
const entry = conversation[i];
|
|
76
|
+
|
|
77
|
+
// output이 아니면 패스
|
|
78
|
+
if (entry?.type !== 'function_call_output') {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const outputCallId = entry.call_id;
|
|
83
|
+
|
|
84
|
+
// call_id가 없거나, 대응하는 function_call이 없으면 고아
|
|
85
|
+
const isOrphan = !outputCallId || !existingCallIds.has(outputCallId);
|
|
86
|
+
|
|
87
|
+
if (isOrphan) {
|
|
88
|
+
orphanIndexes.push(i);
|
|
89
|
+
debugLog(`[cleanupOrphanOutputs] Found orphan at index ${i}, call_id: ${outputCallId}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 3단계: 고아들을 뒤에서부터 제거 (앞에서부터 지우면 인덱스가 밀림)
|
|
94
|
+
for (let i = orphanIndexes.length - 1; i >= 0; i--) {
|
|
95
|
+
const indexToRemove = orphanIndexes[i];
|
|
96
|
+
conversation.splice(indexToRemove, 1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
debugLog(`[cleanupOrphanOutputs] Removed ${orphanIndexes.length} orphans. New length: ${conversation.length}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 컨텍스트 윈도우 초과 시 대화를 줄입니다.
|
|
104
|
+
* 시스템 프롬프트(인덱스 0)를 제외한 가장 오래된 항목(인덱스 1)을 제거합니다.
|
|
105
|
+
*
|
|
106
|
+
* @param {Array} conversation - 대화 배열
|
|
107
|
+
* @returns {boolean} 제거 성공 여부
|
|
108
|
+
*/
|
|
109
|
+
export function trimConversation(conversation) {
|
|
110
|
+
// 시스템 프롬프트와 최소한 하나의 항목이 필요
|
|
111
|
+
if (conversation.length <= 2) {
|
|
112
|
+
debugLog(`[trimConversation] Cannot trim - conversation too short (${conversation.length} entries)`);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 인덱스 1 (시스템 프롬프트 제외 첫 번째 항목) 선택
|
|
117
|
+
const targetEntry = conversation[1];
|
|
118
|
+
const targetCallId = targetEntry?.call_id;
|
|
119
|
+
|
|
120
|
+
debugLog(`[trimConversation] Target entry at index 1: type=${targetEntry?.type}, call_id=${targetCallId}`);
|
|
121
|
+
|
|
122
|
+
// 먼저 인덱스 1 항목 제거
|
|
123
|
+
conversation.splice(1, 1);
|
|
124
|
+
debugLog(`[trimConversation] Removed entry at index 1`);
|
|
125
|
+
|
|
126
|
+
// call_id가 있으면 같은 call_id를 가진 다른 항목들도 제거
|
|
127
|
+
if (targetCallId) {
|
|
128
|
+
removeEntriesWithCallId(conversation, targetCallId);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
debugLog(`[trimConversation] Trim completed. New conversation length: ${conversation.length}`);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
@@ -43,8 +43,7 @@ async function willDefinitelyFail(toolName, args) {
|
|
|
43
43
|
try {
|
|
44
44
|
const absolutePath = resolve(args.file_path);
|
|
45
45
|
|
|
46
|
-
//
|
|
47
|
-
// 편집 도구는 반드시 먼저 read_file로 읽어야 함
|
|
46
|
+
// 스냅샷 확인 (파일을 먼저 read_file로 읽었는지 확인)
|
|
48
47
|
const snapshot = getFileSnapshot(absolutePath);
|
|
49
48
|
const content = snapshot?.content;
|
|
50
49
|
|
|
@@ -53,7 +52,7 @@ async function willDefinitelyFail(toolName, args) {
|
|
|
53
52
|
return { willFail: true, reason: 'File not read yet or empty' };
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
// old_string이
|
|
55
|
+
// old_string이 스냅샷에 없는 경우
|
|
57
56
|
const oldString = args.old_string || '';
|
|
58
57
|
if (!content.includes(oldString)) {
|
|
59
58
|
return { willFail: true, reason: 'old_string not found in file' };
|
|
@@ -64,13 +63,12 @@ async function willDefinitelyFail(toolName, args) {
|
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
// edit_file_range: 스냅샷이
|
|
66
|
+
// edit_file_range: 스냅샷이 없거나 라인 범위가 잘못된 경우
|
|
68
67
|
if (toolName === 'edit_file_range') {
|
|
69
68
|
try {
|
|
70
69
|
const absolutePath = resolve(args.file_path);
|
|
71
70
|
|
|
72
|
-
//
|
|
73
|
-
// 편집 도구는 반드시 먼저 read_file로 읽어야 함
|
|
71
|
+
// 스냅샷 확인 (파일을 먼저 read_file로 읽었는지 확인)
|
|
74
72
|
const snapshot = getFileSnapshot(absolutePath);
|
|
75
73
|
const content = snapshot?.content;
|
|
76
74
|
|
|
@@ -78,6 +76,19 @@ async function willDefinitelyFail(toolName, args) {
|
|
|
78
76
|
if (content === undefined || content === null) {
|
|
79
77
|
return { willFail: true, reason: 'File not read yet or empty' };
|
|
80
78
|
}
|
|
79
|
+
|
|
80
|
+
// 라인 범위 검증
|
|
81
|
+
const lines = content.split('\n');
|
|
82
|
+
const totalLines = content === '' ? 0 :
|
|
83
|
+
(content.endsWith('\n') ? lines.length - 1 : lines.length);
|
|
84
|
+
|
|
85
|
+
if (args.start_line < 1 || args.end_line < args.start_line - 1) {
|
|
86
|
+
return { willFail: true, reason: 'Invalid line range' };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (args.start_line > totalLines + 1 || args.end_line > totalLines) {
|
|
90
|
+
return { willFail: true, reason: `Line range exceeds file length (${totalLines} lines)` };
|
|
91
|
+
}
|
|
81
92
|
} catch (error) {
|
|
82
93
|
return { willFail: true, reason: `Validation error: ${error.message}` };
|
|
83
94
|
}
|
package/src/tools/code_editor.js
CHANGED
|
@@ -442,7 +442,6 @@ export async function edit_file_replace({ file_path, old_string, new_string }) {
|
|
|
442
442
|
return {
|
|
443
443
|
operation_successful: true,
|
|
444
444
|
target_file_path: absolutePath,
|
|
445
|
-
absolute_file_path: absolutePath,
|
|
446
445
|
replacement_count: replacementCount,
|
|
447
446
|
fileSnapshot: fileSnapshot, // UI 히스토리에서 정확한 diff 표시를 위해 편집 전 스냅샷 포함
|
|
448
447
|
file_stats: {
|
|
@@ -654,7 +653,6 @@ export async function edit_file_range({ file_path, start_line, end_line, new_con
|
|
|
654
653
|
operation_successful: true,
|
|
655
654
|
operation_type: operationType,
|
|
656
655
|
target_file_path: absolutePath,
|
|
657
|
-
absolute_file_path: absolutePath,
|
|
658
656
|
fileSnapshot: fileSnapshot, // UI 히스토리에서 정확한 diff 표시를 위해 편집 전 스냅샷 포함
|
|
659
657
|
file_stats: {
|
|
660
658
|
updated_content: newFileContent // 수정 후 전체 파일 내용
|
package/src/tools/file_reader.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { safeReadFile } from '../util/safe_fs.js';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
3
4
|
import { trackFileRead, saveFileSnapshot } from '../system/file_integrity.js';
|
|
4
5
|
import { createDebugLogger } from '../util/debug_log.js';
|
|
5
6
|
import { toDisplayPath } from '../util/path_helper.js';
|
|
@@ -77,6 +78,11 @@ export async function read_file({ filePath }) {
|
|
|
77
78
|
saveFileSnapshot(absolutePath, content);
|
|
78
79
|
debugLog(`Snapshot saved`);
|
|
79
80
|
|
|
81
|
+
// MD5 해시 계산
|
|
82
|
+
debugLog(`Calculating MD5 hash...`);
|
|
83
|
+
const md5Hash = createHash('md5').update(content).digest('hex');
|
|
84
|
+
debugLog(`MD5 hash: ${md5Hash}`);
|
|
85
|
+
|
|
80
86
|
debugLog('========== read_file SUCCESS END ==========');
|
|
81
87
|
|
|
82
88
|
return {
|
|
@@ -84,8 +90,7 @@ export async function read_file({ filePath }) {
|
|
|
84
90
|
target_file_path: absolutePath,
|
|
85
91
|
total_line_count: totalLines,
|
|
86
92
|
file_content: content,
|
|
87
|
-
|
|
88
|
-
(content.endsWith('\n') ? lines.slice(0, -1) : lines)
|
|
93
|
+
md5_hash: md5Hash
|
|
89
94
|
};
|
|
90
95
|
} catch (error) {
|
|
91
96
|
debugLog(`========== read_file EXCEPTION ==========`);
|
|
@@ -200,6 +205,11 @@ export async function read_file_range({ filePath, startLine, endLine }) {
|
|
|
200
205
|
saveFileSnapshot(absolutePath, content);
|
|
201
206
|
debugLog(`Snapshot saved`);
|
|
202
207
|
|
|
208
|
+
// MD5 해시 계산 (전체 파일 내용에 대해)
|
|
209
|
+
debugLog(`Calculating MD5 hash...`);
|
|
210
|
+
const md5Hash = createHash('md5').update(content).digest('hex');
|
|
211
|
+
debugLog(`MD5 hash: ${md5Hash}`);
|
|
212
|
+
|
|
203
213
|
// 라인 번호 유효성 검사 (1부터 시작)
|
|
204
214
|
debugLog(`Validating line range...`);
|
|
205
215
|
if (startLine < 1) {
|
|
@@ -225,16 +235,6 @@ export async function read_file_range({ filePath, startLine, endLine }) {
|
|
|
225
235
|
const selectedLines = actualLines.slice(startLine - 1, endLine);
|
|
226
236
|
debugLog(`Extracted ${selectedLines.length} lines`);
|
|
227
237
|
|
|
228
|
-
const numberedLines = selectedLines.map((line, index) => ({
|
|
229
|
-
line_number: startLine + index,
|
|
230
|
-
line_content: line
|
|
231
|
-
}));
|
|
232
|
-
|
|
233
|
-
// file_content에 라인 번호 추가
|
|
234
|
-
const contentWithLineNumbers = selectedLines
|
|
235
|
-
.map((line, index) => `${startLine + index}| ${line}`)
|
|
236
|
-
.join('\n');
|
|
237
|
-
|
|
238
238
|
debugLog('========== read_file_range SUCCESS END ==========');
|
|
239
239
|
|
|
240
240
|
return {
|
|
@@ -246,7 +246,8 @@ export async function read_file_range({ filePath, startLine, endLine }) {
|
|
|
246
246
|
start_line: startLine,
|
|
247
247
|
end_line: Math.min(endLine, totalLines)
|
|
248
248
|
},
|
|
249
|
-
file_content:
|
|
249
|
+
file_content: selectedLines.join('\n'),
|
|
250
|
+
md5_hash: md5Hash
|
|
250
251
|
};
|
|
251
252
|
} catch (error) {
|
|
252
253
|
debugLog(`========== read_file_range EXCEPTION ==========`);
|
|
@@ -299,7 +300,7 @@ export const readFileRangeSchema = {
|
|
|
299
300
|
},
|
|
300
301
|
"format_tool_result": (result) => {
|
|
301
302
|
if (result.operation_successful) {
|
|
302
|
-
const lineCount = result.
|
|
303
|
+
const lineCount = result.file_content ? result.file_content.split('\n').length : 0;
|
|
303
304
|
return {
|
|
304
305
|
type: 'formatted',
|
|
305
306
|
parts: [
|
package/src/util/exit_handler.js
CHANGED
|
@@ -27,6 +27,15 @@ export async function performExit(options = {}) {
|
|
|
27
27
|
await uiEvents.waitForRender();
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
// UI 인스턴스 정리 전에 터미널 상태 복구
|
|
31
|
+
// 이렇게 하면 React cleanup이 실행되지 않아도 터미널 상태가 복구됨
|
|
32
|
+
if (process.stdout && process.stdout.write) {
|
|
33
|
+
// 커서 표시 복구 (App.js:447과 동일)
|
|
34
|
+
process.stdout.write('\x1B[?25h');
|
|
35
|
+
// Line wrapping 복구 (index.js:54와 동일)
|
|
36
|
+
process.stdout.write('\x1b[?7h');
|
|
37
|
+
}
|
|
38
|
+
|
|
30
39
|
// UI 인스턴스 정리
|
|
31
40
|
if (uiInstance) {
|
|
32
41
|
uiInstance.unmount();
|
|
@@ -22,22 +22,20 @@ export function clampOutput(text) {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* 파일 읽기 결과에 줄 번호 추가
|
|
25
|
-
* @param {
|
|
26
|
-
* @
|
|
25
|
+
* @param {string} content - 파일 내용 (문자열)
|
|
26
|
+
* @param {number} startLine - 시작 줄 번호 (기본값: 1)
|
|
27
|
+
* @returns {string} 줄 번호가 포함된 파일 내용
|
|
27
28
|
*/
|
|
28
|
-
export function formatReadFileStdout(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return JSON.stringify(result, null, 2);
|
|
29
|
+
export function formatReadFileStdout(content, startLine = 1) {
|
|
30
|
+
if (!content || typeof content !== 'string') {
|
|
31
|
+
return '';
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
|
|
34
|
+
const lines = content.split('\n');
|
|
35
35
|
let stdout = '';
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
}
|
|
36
|
+
lines.forEach((line, index) => {
|
|
37
|
+
stdout += `${startLine + index}|${line}\n`;
|
|
38
|
+
});
|
|
41
39
|
return stdout;
|
|
42
40
|
}
|
|
43
41
|
|
|
@@ -48,10 +46,5 @@ export function formatReadFileStdout(result) {
|
|
|
48
46
|
* @returns {string} 포맷된 출력
|
|
49
47
|
*/
|
|
50
48
|
export function formatToolStdout(operation, result) {
|
|
51
|
-
|
|
52
|
-
case 'read_file':
|
|
53
|
-
return formatReadFileStdout(result);
|
|
54
|
-
default:
|
|
55
|
-
return JSON.stringify(result, null, 2);
|
|
56
|
-
}
|
|
49
|
+
return JSON.stringify(result, null, 2);
|
|
57
50
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|