synapse-orch-ai 1.5.0 → 1.5.2
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/backend/core/builder_tools.py +24 -1
- package/backend/core/models.py +2 -1
- package/backend/core/native_builder/__init__.py +1 -1
- package/backend/core/native_builder/agents/agent_creator.json +1 -1
- package/backend/core/native_builder/orchestration.json +1 -1
- package/backend/core/routes/agents.py +19 -0
- package/backend/core/routes/repos.py +12 -4
- package/backend/core/routes/tools.py +16 -1
- package/backend/core/server.py +1 -1
- package/backend/core/tools.py +21 -3
- package/backend/services/code_indexer.py +55 -7
- package/backend/tools/code_search.py +299 -5
- package/frontend-build/.next/BUILD_ID +1 -1
- package/frontend-build/.next/build-manifest.json +6 -6
- package/frontend-build/.next/prerender-manifest.json +3 -3
- package/frontend-build/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/frontend-build/.next/server/app/_global-error/page.js +3 -3
- package/frontend-build/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/frontend-build/.next/server/app/_global-error.html +1 -1
- package/frontend-build/.next/server/app/_global-error.rsc +1 -1
- package/frontend-build/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/frontend-build/.next/server/app/_not-found/page/next-font-manifest.json +2 -2
- package/frontend-build/.next/server/app/_not-found/page.js +3 -3
- package/frontend-build/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/frontend-build/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/frontend-build/.next/server/app/_not-found.html +1 -1
- package/frontend-build/.next/server/app/_not-found.rsc +2 -2
- package/frontend-build/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/frontend-build/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/frontend-build/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/frontend-build/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/frontend-build/.next/server/app/index.html +1 -1
- package/frontend-build/.next/server/app/index.rsc +4 -4
- package/frontend-build/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/frontend-build/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/frontend-build/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/frontend-build/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/frontend-build/.next/server/app/index.segments/_tree.segment.rsc +4 -4
- package/frontend-build/.next/server/app/login/page/build-manifest.json +3 -3
- package/frontend-build/.next/server/app/login/page/next-font-manifest.json +2 -2
- package/frontend-build/.next/server/app/login/page.js +3 -3
- package/frontend-build/.next/server/app/login/page.js.nft.json +1 -1
- package/frontend-build/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/frontend-build/.next/server/app/login.html +1 -1
- package/frontend-build/.next/server/app/login.rsc +4 -4
- package/frontend-build/.next/server/app/login.segments/_full.segment.rsc +4 -4
- package/frontend-build/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/frontend-build/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/frontend-build/.next/server/app/login.segments/_tree.segment.rsc +4 -4
- package/frontend-build/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
- package/frontend-build/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/frontend-build/.next/server/app/page/build-manifest.json +3 -3
- package/frontend-build/.next/server/app/page/next-font-manifest.json +2 -2
- package/frontend-build/.next/server/app/page.js +3 -3
- package/frontend-build/.next/server/app/page.js.nft.json +1 -1
- package/frontend-build/.next/server/app/page_client-reference-manifest.js +1 -1
- package/frontend-build/.next/server/app/settings/[tab]/page/build-manifest.json +3 -3
- package/frontend-build/.next/server/app/settings/[tab]/page/next-font-manifest.json +2 -2
- package/frontend-build/.next/server/app/settings/[tab]/page.js +3 -3
- package/frontend-build/.next/server/app/settings/[tab]/page.js.nft.json +1 -1
- package/frontend-build/.next/server/app/settings/[tab]/page_client-reference-manifest.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__00ci3m0._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__01~.b7w._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__066njqe._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__08cioyi._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0df0b6v._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0efx8a5._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0j8-xkl._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0kk2o8d._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0kyyn1g._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0o2ckji._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0r1_rdp._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0s65g6m._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0u8_aw2._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0z5q5.1._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__0~o635_._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__10p49e~._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__115~uq6._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__12ug7cf._.js +1 -1
- package/frontend-build/.next/server/chunks/[root-of-the-server]__12vs3wg._.js +1 -1
- package/frontend-build/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0dh.2jf.js +1 -1
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__098zro9._.js +19 -0
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__0fo_bex._.js +3 -0
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__0lb9jwe._.js +3 -0
- package/frontend-build/.next/server/chunks/ssr/{[root-of-the-server]__09c9368._.js → [root-of-the-server]__0p75w55._.js} +2 -2
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__0rt28lm._.js +3 -0
- package/frontend-build/.next/server/chunks/ssr/{[root-of-the-server]__10xgshr._.js → [root-of-the-server]__0tcyn68._.js} +2 -2
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__0zi~h76._.js +3 -0
- package/frontend-build/.next/server/chunks/ssr/_0b~n.nn._.js +3 -3
- package/frontend-build/.next/server/chunks/ssr/node_modules_0_ce7g1._.js +1 -1
- package/frontend-build/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js +1 -1
- package/frontend-build/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_00t_ate.js +2 -2
- package/frontend-build/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_031v14j.js +2 -2
- package/frontend-build/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0328vov.js +2 -2
- package/frontend-build/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0p6f2go.js +2 -2
- package/frontend-build/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +2 -2
- package/frontend-build/.next/server/edge/chunks/[root-of-the-server]__08ca2jv._.js +2 -2
- package/frontend-build/.next/server/middleware-build-manifest.js +6 -6
- package/frontend-build/.next/server/middleware-manifest.json +6 -6
- package/frontend-build/.next/server/next-font-manifest.js +1 -1
- package/frontend-build/.next/server/next-font-manifest.json +8 -8
- package/frontend-build/.next/server/pages/404.html +1 -1
- package/frontend-build/.next/server/pages/500.html +1 -1
- package/frontend-build/.next/server/server-reference-manifest.js +1 -1
- package/frontend-build/.next/server/server-reference-manifest.json +1 -1
- package/frontend-build/.next/static/chunks/{0j29xn-eqm8iz.css → 0.kqnisf2zxq0.css} +2 -2
- package/frontend-build/.next/static/chunks/{0h4a4y-~puu.x.js → 00xhsd~k-wxkl.js} +1 -1
- package/frontend-build/.next/static/chunks/0c7h~x4_chf35.js +2 -0
- package/frontend-build/.next/static/chunks/{15z7zp13idekl.js → 0p-n32n5uskl..js} +2 -2
- package/frontend-build/.next/static/chunks/{turbopack-0~_lks..-4osp.js → turbopack-09lztqg9--eu..js} +1 -1
- package/frontend-build/.next/static/{47MXNuH5FrJAfrk7sJf9l → fsuDyqiporr4Vnz4Atiql}/_clientMiddlewareManifest.js +1 -1
- package/frontend-build/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
- package/frontend-build/.next/static/media/53b9e256198e5412-s.0-wfv7uh4i7h9.woff2 +0 -0
- package/frontend-build/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
- package/frontend-build/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
- package/frontend-build/.next/static/media/7178b3e590c64307-s.0nx0ww8fni_q3.woff2 +0 -0
- package/frontend-build/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
- package/frontend-build/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
- package/frontend-build/.next/static/media/8a480f0b521d4e75-s.0jzbimsg8vl84.woff2 +0 -0
- package/frontend-build/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
- package/frontend-build/.next/static/media/caa3a2e1cccd8315-s.p.09~u27dqhyhd6.woff2 +0 -0
- package/frontend-build/.next/static/media/fef07dbb0973bf53-s.12tyk43_3sh9u.woff2 +0 -0
- package/frontend-build/node_modules/@next/env/package.json +1 -1
- package/frontend-build/node_modules/next/dist/build/static-paths/app.js +2 -1
- package/frontend-build/node_modules/next/dist/build/swc/index.js +1 -1
- package/frontend-build/node_modules/next/dist/build/utils.js +2 -1
- package/frontend-build/node_modules/next/dist/client/components/router-reducer/fetch-server-response.js +2 -2
- package/frontend-build/node_modules/next/dist/client/components/router-reducer/set-cache-busting-search-param.js +8 -2
- package/frontend-build/node_modules/next/dist/client/route-params.js +23 -6
- package/frontend-build/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +13 -13
- package/frontend-build/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +11 -11
- package/frontend-build/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +2 -2
- package/frontend-build/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +10 -10
- package/frontend-build/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/frontend-build/node_modules/next/dist/server/app-render/action-handler.js +3 -6
- package/frontend-build/node_modules/next/dist/server/app-render/app-render.js +62 -9
- package/frontend-build/node_modules/next/dist/server/app-render/collect-segment-data.js +16 -0
- package/frontend-build/node_modules/next/dist/server/app-render/create-component-tree.js +49 -19
- package/frontend-build/node_modules/next/dist/server/app-render/get-script-nonce-from-header.js +8 -20
- package/frontend-build/node_modules/next/dist/server/app-render/metadata-insertion/create-server-inserted-metadata.js +8 -7
- package/frontend-build/node_modules/next/dist/server/app-render/use-flight-response.js +2 -2
- package/frontend-build/node_modules/next/dist/server/async-storage/work-store.js +2 -1
- package/frontend-build/node_modules/next/dist/server/base-server.js +13 -5
- package/frontend-build/node_modules/next/dist/server/config-schema.js +10 -2
- package/frontend-build/node_modules/next/dist/server/config.js +1 -1
- package/frontend-build/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/frontend-build/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/frontend-build/node_modules/next/dist/server/dev/static-paths-worker.js +2 -1
- package/frontend-build/node_modules/next/dist/server/image-optimizer.js +22 -2
- package/frontend-build/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/frontend-build/node_modules/next/dist/server/lib/is-rsc-request.js +18 -0
- package/frontend-build/node_modules/next/dist/server/lib/mock-request.js +30 -5
- package/frontend-build/node_modules/next/dist/server/lib/patch-set-header.js +7 -0
- package/frontend-build/node_modules/next/dist/server/lib/router-server.js +6 -3
- package/frontend-build/node_modules/next/dist/server/lib/router-utils/resolve-routes.js +18 -4
- package/frontend-build/node_modules/next/dist/server/lib/server-ipc/utils.js +3 -1
- package/frontend-build/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/frontend-build/node_modules/next/dist/server/next-server.js +1 -1
- package/frontend-build/node_modules/next/dist/server/render.js +27 -20
- package/frontend-build/node_modules/next/dist/server/request/fallback-params.js +27 -1
- package/frontend-build/node_modules/next/dist/server/route-modules/app-route/module.js +1 -0
- package/frontend-build/node_modules/next/dist/server/route-modules/route-module.js +11 -1
- package/frontend-build/node_modules/next/dist/server/server-utils.js +19 -2
- package/frontend-build/node_modules/next/dist/server/stream-utils/node-web-streams-helper.js +5 -5
- package/frontend-build/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +1 -1
- package/frontend-build/node_modules/next/dist/server/web/adapter.js +4 -1
- package/frontend-build/node_modules/next/dist/server/web/edge-route-module-wrapper.js +2 -1
- package/frontend-build/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- package/frontend-build/node_modules/next/dist/{server → shared/lib}/htmlescape.js +15 -0
- package/frontend-build/node_modules/next/dist/shared/lib/router/routes/app.js +13 -1
- package/frontend-build/node_modules/next/dist/shared/lib/router/utils/cache-busting-search-param.js +56 -10
- package/frontend-build/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/frontend-build/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/frontend-build/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/frontend-build/node_modules/next/package.json +15 -15
- package/frontend-build/package.json +1 -1
- package/package.json +1 -1
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__08l1kmh._.js +0 -3
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__09z7o2x._.js +0 -19
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__0ffv7p5._.js +0 -3
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__0m2-0f1._.js +0 -3
- package/frontend-build/.next/server/chunks/ssr/[root-of-the-server]__120kr3r._.js +0 -3
- package/frontend-build/.next/static/chunks/0e-wrhqh4h3r5.js +0 -2
- package/frontend-build/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
- package/frontend-build/.next/static/media/7178b3e590c64307-s.11.cyxs5p-0z~.woff2 +0 -0
- package/frontend-build/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
- package/frontend-build/.next/static/media/8a480f0b521d4e75-s.06d3mdzz5bre_.woff2 +0 -0
- package/frontend-build/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
- package/frontend-build/.next/static/media/caa3a2e1cccd8315-s.p.16t1db8_9y2o~.woff2 +0 -0
- /package/frontend-build/.next/static/{47MXNuH5FrJAfrk7sJf9l → fsuDyqiporr4Vnz4Atiql}/_buildManifest.js +0 -0
- /package/frontend-build/.next/static/{47MXNuH5FrJAfrk7sJf9l → fsuDyqiporr4Vnz4Atiql}/_ssgManifest.js +0 -0
|
@@ -98,7 +98,8 @@ BUILDER_TOOL_SCHEMAS = [
|
|
|
98
98
|
"description": (
|
|
99
99
|
"Create a new agent and save it. Returns the created agent with its new ID. "
|
|
100
100
|
"Use type='conversational' for general-purpose agents, 'code' for agents that work with repos/files, "
|
|
101
|
-
"'orchestrator' for agents that run orchestrations
|
|
101
|
+
"'orchestrator' for agents that run orchestrations, "
|
|
102
|
+
"'delegate' for agents that dynamically route queries to sub-agents (set delegate_agent_ids to restrict which agents it can delegate to; empty = all agents). "
|
|
102
103
|
"Set tools=['all'] to give access to all tools, or list specific tool names."
|
|
103
104
|
),
|
|
104
105
|
"parameters": {
|
|
@@ -134,6 +135,11 @@ BUILDER_TOOL_SCHEMAS = [
|
|
|
134
135
|
"items": {"type": "string"},
|
|
135
136
|
"description": "List of DB config IDs (for agents needing database access).",
|
|
136
137
|
},
|
|
138
|
+
"delegate_agent_ids": {
|
|
139
|
+
"type": "array",
|
|
140
|
+
"items": {"type": "string"},
|
|
141
|
+
"description": "For delegate agents: list of agent IDs to restrict delegation to. Leave empty to allow delegation to any agent.",
|
|
142
|
+
},
|
|
137
143
|
},
|
|
138
144
|
"required": ["name", "description", "type", "tools", "system_prompt"],
|
|
139
145
|
},
|
|
@@ -184,6 +190,11 @@ BUILDER_TOOL_SCHEMAS = [
|
|
|
184
190
|
"type": "array",
|
|
185
191
|
"items": {"type": "string"},
|
|
186
192
|
},
|
|
193
|
+
"delegate_agent_ids": {
|
|
194
|
+
"type": "array",
|
|
195
|
+
"items": {"type": "string"},
|
|
196
|
+
"description": "For delegate agents: agent IDs to restrict delegation to. Empty = allow any agent.",
|
|
197
|
+
},
|
|
187
198
|
},
|
|
188
199
|
"required": ["name", "description", "type", "tools", "system_prompt"],
|
|
189
200
|
},
|
|
@@ -623,6 +634,14 @@ BUILDER_TOOL_SCHEMAS = [
|
|
|
623
634
|
"max_turns": {"type": "integer", "description": "Max agent turns (default 15)"},
|
|
624
635
|
"timeout_seconds": {"type": "integer", "description": "Step timeout (default 300)"},
|
|
625
636
|
"model": {"type": "string", "description": "LLM model override for this step"},
|
|
637
|
+
"include_full_history": {
|
|
638
|
+
"type": "boolean",
|
|
639
|
+
"description": (
|
|
640
|
+
"For agent/llm/tool steps: on re-invocation (evaluator loop-back or retry), "
|
|
641
|
+
"include every prior turn's inputs, tools, and output instead of only the last attempt. "
|
|
642
|
+
"Useful for feedback loops; increases prompt length."
|
|
643
|
+
),
|
|
644
|
+
},
|
|
626
645
|
},
|
|
627
646
|
"required": ["orch_id", "step_id", "name", "type"],
|
|
628
647
|
},
|
|
@@ -679,6 +698,7 @@ BUILDER_TOOL_SCHEMAS = [
|
|
|
679
698
|
"max_turns": {"type": "integer"},
|
|
680
699
|
"timeout_seconds": {"type": "integer"},
|
|
681
700
|
"model": {"type": "string"},
|
|
701
|
+
"include_full_history": {"type": "boolean", "description": "Include full revision history on re-invocation (agent/llm/tool steps)"},
|
|
682
702
|
},
|
|
683
703
|
"required": ["step_id", "name", "type"],
|
|
684
704
|
},
|
|
@@ -752,6 +772,7 @@ async def _dispatch(tool_name: str, args: dict, server_module: Any) -> Any:
|
|
|
752
772
|
"model": args.get("model") or None,
|
|
753
773
|
"provider": None,
|
|
754
774
|
"max_turns": None,
|
|
775
|
+
"delegate_agent_ids": args.get("delegate_agent_ids", []) or [],
|
|
755
776
|
}
|
|
756
777
|
agents.append(agent)
|
|
757
778
|
save_user_agents(agents)
|
|
@@ -793,6 +814,7 @@ async def _dispatch(tool_name: str, args: dict, server_module: Any) -> Any:
|
|
|
793
814
|
"model": spec.get("model") or None,
|
|
794
815
|
"provider": None,
|
|
795
816
|
"max_turns": None,
|
|
817
|
+
"delegate_agent_ids": spec.get("delegate_agent_ids", []) or [],
|
|
796
818
|
}
|
|
797
819
|
agents.append(agent)
|
|
798
820
|
created.append({
|
|
@@ -1559,6 +1581,7 @@ def _fill_step_defaults(steps: list) -> list:
|
|
|
1559
1581
|
s.setdefault("switch_expression", None)
|
|
1560
1582
|
s.setdefault("switch_cases", {})
|
|
1561
1583
|
s.setdefault("switch_default_step_id", None)
|
|
1584
|
+
s.setdefault("include_full_history", None)
|
|
1562
1585
|
result.append(s)
|
|
1563
1586
|
return result
|
|
1564
1587
|
|
package/backend/core/models.py
CHANGED
|
@@ -59,7 +59,7 @@ class Repo(BaseModel):
|
|
|
59
59
|
name: str
|
|
60
60
|
path: str
|
|
61
61
|
description: str = ""
|
|
62
|
-
included_patterns: list[str] = ["*.py", "*.ts", "*.tsx", "*.js", "*.jsx", "*.rs", "*.go", "*.java", "*.md", "*.html", "*.vue", "*.css", "*.scss", "*.cpp", "*.c"]
|
|
62
|
+
included_patterns: list[str] = ["*.py", "*.ts", "*.tsx", "*.js", "*.jsx", "*.rs", "*.go", "*.java", "*.md", "*.html", "*.vue", "*.svelte", "*.css", "*.scss", "*.cpp", "*.c"]
|
|
63
63
|
excluded_patterns: list[str] = [".*", "node_modules", "__pycache__", "venv", ".git", "*.pyc"]
|
|
64
64
|
last_indexed: str | None = None
|
|
65
65
|
status: str = "pending" # pending | indexing | indexed | error
|
|
@@ -152,6 +152,7 @@ class GeneratePromptRequest(BaseModel):
|
|
|
152
152
|
agent_type: str = "conversational"
|
|
153
153
|
tools: list[str] = []
|
|
154
154
|
existing_prompt: str = ""
|
|
155
|
+
agents: list[dict] = [] # list of {id, name, description, type} — for delegate agents
|
|
155
156
|
|
|
156
157
|
|
|
157
158
|
class GoogleCredsRequest(BaseModel):
|
|
@@ -24,7 +24,7 @@ __all__ = [
|
|
|
24
24
|
# their zero-defaults (`route_map: {}`, `parallel_branches: []`, etc.) so the
|
|
25
25
|
# engine deserialises cleanly.
|
|
26
26
|
STEP_TYPE_CHEATSHEET = """\
|
|
27
|
-
- **agent**: runs a configured sub-agent with a prompt + its tool set. Required: `agent_id`, `prompt_template`. Use for any step that needs multi-turn reasoning or tool use.
|
|
27
|
+
- **agent**: runs a configured sub-agent with a prompt + its tool set. Required: `agent_id`, `prompt_template`. Optional: `include_full_history` (bool) — on re-invocation show every prior turn's inputs/tools/output instead of only the last attempt; useful for feedback/retry loops. Use for any step that needs multi-turn reasoning or tool use.
|
|
28
28
|
- **llm**: single one-shot LLM call, no tools. Required: `prompt_template` (optional `model`). Use for lightweight summarisation, rewriting, or deterministic prose generation.
|
|
29
29
|
- **tool**: forces a single tool call with no LLM reasoning. Required: `forced_tool` (+ `agent_id` for tool-resolution). Use when the arguments are already in state and just need forwarding.
|
|
30
30
|
- **evaluator**: pure routing node. Required: `route_map_json` (JSON-encoded `{label: target_step_id}`), `route_descriptions_json` (JSON), `evaluator_prompt`. Output_key stores the bare route label. Use to fork on a classifier decision.
|
|
@@ -16,5 +16,5 @@
|
|
|
16
16
|
],
|
|
17
17
|
"repos": [],
|
|
18
18
|
"db_configs": [],
|
|
19
|
-
"system_prompt": "# Role\nYou are the Agent Creator for the Synapse AI Builder. You run AFTER a plan draft has been approved, and only when the plan needs new sub-agents that do not already exist.\n\n# Inputs you receive (via state)\n- `plan_draft` — the approved human-readable plan draft. It lists each role. For each new agent it includes bullets for **purpose**, **tools**, **repos**, and **type**.\n- `selected_agent_ids` — agent IDs the user pre-selected. Treat these as already-existing; do NOT recreate them.\n- `can_create_agents` — must be true to reach this step. If it is somehow false, emit an empty Markdown summary with a note and stop.\n\n# What to do — strict order\n\n1. **Parse the draft.** Read the **New agents to create** section. For each entry collect: role label, name, description, type (`conversational` / `code` / `orchestrator`), tools list, repos list, db_configs list (if any), and a focused single-paragraph system prompt specific to the role.\n\n2. **Resolve repo IDs (only if any new agent has a non-empty repos list).** Call `list_repos` ONCE. Match repo names from the draft to real repo IDs. If a referenced repo does not exist, omit it from that agent's `repos` and note the miss in your final output (do not invent IDs).\n\n3. **Create the agents in ONE batch.** Call `create_agents` exactly once with the full array. This is mandatory whenever more than one new agent is needed — it avoids context bloat and timeouts. Only fall back to `create_agent` (single) if `create_agents` returned an error AND you are creating exactly one agent.\n\n4. **Emit the Markdown summary.** Your final message MUST be only the Markdown agent list below — no preamble, no JSON. One `##` section per agent (new AND pre-existing). For pre-existing agents set **Existing:** yes.\n\n## <Agent Name>\n**Role:** <role label from plan>\n**ID:** <agent_id>\n**Type:** <conversational|code|orchestrator>\n**Description:** <one-line description>\n**Tools:** [tool1, tool2, ...]\n**Repos:** [repo_id, ...] *(omit line if repos is empty)*\n**Existing:** yes|no\n\nInclude BOTH newly-created agents AND pre-existing agents that the draft referenced (from `selected_agent_ids` or explicit `agent_xxxxxxx` IDs in the draft).\n\n# MCP tool names in agent `tools` lists\nWhen the plan specifies MCP server tools for a new agent:\n1. Call `list_tool_servers` ONCE to see available servers (name + type).\n2. Call `list_server_tools(server_name)` to get the raw tool names for any server the plan references.\n3. Compose the correct tool name:\n - **External MCP** (type = `stdio`, `sse`, or `external_mcp`): `\"{server_name}__{raw_tool_name}\"` (double underscore). Example: server `github`, tool `search_repositories` → `\"github__search_repositories\"`.\n - **Native MCP** (type = `native_mcp`): just `\"{raw_tool_name}\"` — no prefix.\n4. Use these composed names in the `tools` array when calling `create_agents`.\n\nNever guess MCP tool names — always discover them via the tools above.\n\n# Hard rules\n- **Never invent agent IDs.** Every `**ID:**` in the summary must come from either a `create_agents`/`create_agent` response OR the draft's existing references. If you did not call the tool, you do not have an ID. Period.\n- **Never modify existing agents** in this step.\n- **Keep each new agent's system prompt tight and role-specific.** Do not copy the full plan into it.\n- **Narrow `tools` list.** Include only what the role actually needs. Never `[\"all\"]` unless the role genuinely needs everything.\n- **Repos belong on `code`-type agents** (or any agent that must read/write code). Conversational agents usually have `repos: []`.\n- **Output only the Markdown summary** — no preamble, no explanations, no JSON. The saver reads this directly.\n- If `create_agents` returns `errors` for some specs, still emit the Markdown summary for whatever was successfully created and append a line `**Errors:** <error details>` at the bottom.\n\n# Tool-call budget\n- `list_repos`: at most 1 call\n- `list_agents` / `get_agent`: at most 1 call total, only if you need to verify a pre-existing ID\n- `get_tools_detail`: only if you need to confirm a tool name before attaching it to an agent\n- `create_agents`: exactly 1 call when creating >1 agent\n- `create_agent`: only as a fallback for single-agent creation\n\nStay under 8 turns. Do NOT retry a failed `create_agents` call more than once."
|
|
19
|
+
"system_prompt": "# Role\nYou are the Agent Creator for the Synapse AI Builder. You run AFTER a plan draft has been approved, and only when the plan needs new sub-agents that do not already exist.\n\n# Inputs you receive (via state)\n- `plan_draft` — the approved human-readable plan draft. It lists each role. For each new agent it includes bullets for **purpose**, **tools**, **repos**, and **type**.\n- `selected_agent_ids` — agent IDs the user pre-selected. Treat these as already-existing; do NOT recreate them.\n- `can_create_agents` — must be true to reach this step. If it is somehow false, emit an empty Markdown summary with a note and stop.\n\n# What to do — strict order\n\n1. **Parse the draft.** Read the **New agents to create** section. For each entry collect: role label, name, description, type (`conversational` / `code` / `orchestrator` / `delegate`), tools list, repos list, db_configs list (if any), delegate_agent_ids list (for delegate type only — empty list means any agent), and a focused single-paragraph system prompt specific to the role.\n\n2. **Resolve repo IDs (only if any new agent has a non-empty repos list).** Call `list_repos` ONCE. Match repo names from the draft to real repo IDs. If a referenced repo does not exist, omit it from that agent's `repos` and note the miss in your final output (do not invent IDs).\n\n3. **Create the agents in ONE batch.** Call `create_agents` exactly once with the full array. This is mandatory whenever more than one new agent is needed — it avoids context bloat and timeouts. Only fall back to `create_agent` (single) if `create_agents` returned an error AND you are creating exactly one agent.\n\n4. **Emit the Markdown summary.** Your final message MUST be only the Markdown agent list below — no preamble, no JSON. One `##` section per agent (new AND pre-existing). For pre-existing agents set **Existing:** yes.\n\n## <Agent Name>\n**Role:** <role label from plan>\n**ID:** <agent_id>\n**Type:** <conversational|code|orchestrator|delegate>\n**Description:** <one-line description>\n**Tools:** [tool1, tool2, ...]\n**Repos:** [repo_id, ...] *(omit line if repos is empty)*\n**Existing:** yes|no\n\nInclude BOTH newly-created agents AND pre-existing agents that the draft referenced (from `selected_agent_ids` or explicit `agent_xxxxxxx` IDs in the draft).\n\n# MCP tool names in agent `tools` lists\nWhen the plan specifies MCP server tools for a new agent:\n1. Call `list_tool_servers` ONCE to see available servers (name + type).\n2. Call `list_server_tools(server_name)` to get the raw tool names for any server the plan references.\n3. Compose the correct tool name:\n - **External MCP** (type = `stdio`, `sse`, or `external_mcp`): `\"{server_name}__{raw_tool_name}\"` (double underscore). Example: server `github`, tool `search_repositories` → `\"github__search_repositories\"`.\n - **Native MCP** (type = `native_mcp`): just `\"{raw_tool_name}\"` — no prefix.\n4. Use these composed names in the `tools` array when calling `create_agents`.\n\nNever guess MCP tool names — always discover them via the tools above.\n\n# Hard rules\n- **Never invent agent IDs.** Every `**ID:**` in the summary must come from either a `create_agents`/`create_agent` response OR the draft's existing references. If you did not call the tool, you do not have an ID. Period.\n- **Never modify existing agents** in this step.\n- **Keep each new agent's system prompt tight and role-specific.** Do not copy the full plan into it.\n- **Narrow `tools` list.** Include only what the role actually needs. Never `[\"all\"]` unless the role genuinely needs everything.\n- **Repos belong on `code`-type agents** (or any agent that must read/write code). Conversational agents usually have `repos: []`.\n- **`delegate_agent_ids` belongs on `delegate`-type agents only.** Pass the list of agent IDs the agent may route to, or an empty list to allow routing to any agent. Omit this field for all other types.\n- **Output only the Markdown summary** — no preamble, no explanations, no JSON. The saver reads this directly.\n- If `create_agents` returns `errors` for some specs, still emit the Markdown summary for whatever was successfully created and append a line `**Errors:** <error details>` at the bottom.\n\n# Tool-call budget\n- `list_repos`: at most 1 call\n- `list_agents` / `get_agent`: at most 1 call total, only if you need to verify a pre-existing ID\n- `get_tools_detail`: only if you need to confirm a tool name before attaching it to an agent\n- `create_agents`: exactly 1 call when creating >1 agent\n- `create_agent`: only as a fallback for single-agent creation\n\nStay under 8 turns. Do NOT retry a failed `create_agents` call more than once."
|
|
20
20
|
}
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
"name": "Draft Plan",
|
|
197
197
|
"type": "llm",
|
|
198
198
|
"agent_id": null,
|
|
199
|
-
"prompt_template": "You are the Plan Drafter for the Synapse AI Builder. Produce a HUMAN-READABLE markdown draft of the orchestration plan. The user will read this next and either approve it or send revision feedback. After approval, a saver agent reads this draft to materialise the real orchestration JSON, so the draft must be precise enough to act on.\n\n# Inputs\nIntent: {state.intent}\n\nRequirements spec:\n{state.requirements}\n\nExisting orchestration (only on update; empty otherwise):\n{state.existing_orch}\n\nPre-selected agent IDs: {state.selected_agent_ids}\nCan create new agents: {state.can_create_agents}\n\nPrevious draft (empty on first pass):\n{state.plan_draft}\n\nUser's revision feedback on the previous draft (empty on first pass):\n{state.review_feedback}\n\n# Step-type palette (use these — never invent a type)\n{{STEP_TYPE_CHEATSHEET}}\n\n# What to write\nMarkdown with these sections, in this order:\n\n## Overview\nOne paragraph: what the orchestration does end-to-end. On update, call out what is changing vs the existing definition.\n\n## State schema\nBullet list of state keys with type and one-line purpose.\n\n## Steps\nNumbered list. For each step:\n- **Name** (step type: one of agent / llm / evaluator / human / parallel / merge / loop / transform / tool / end)\n- What it does, its input keys, its output key, and its next step (or route map for evaluators).\n- For agent steps: role name AND whether it maps to an existing agent (`agent_xxxxxxx`) or a NEW agent to create (describe its job + tools).\n- For tool steps: the forced tool name. If you are uncertain a tool exists, flag it under Open questions rather than guessing.\n- For human steps: the prompt the user will see and the fields collected.\n\n## Agents summary\nTwo short lists:\n- **Existing agents reused**: one line each — `role → agent_id (name)`.\n- **New agents to create**: one block per new agent. Each block uses this exact shape so the downstream Agent Creator can parse it deterministically:\n - `role: <role_label>` — short identifier used elsewhere in the plan (e.g. `question_generator`).\n - `name: <Display Name>` — what the agent will be called.\n - `type: conversational | code | orchestrator` — pick `code` ONLY if the agent reads/writes a repo; pick `orchestrator` only if it runs a sub-orchestration; everything else is `conversational`.\n - `purpose: <one sentence>` — what this agent does end-to-end.\n - `tools: [tool_name, tool_name]` — narrow list, only what the role needs. Use real tool names (confirmed by the analyst via `get_tools_detail`). Never `[\"all\"]`.\n - `repos: [repo_id, repo_id]` — real repo IDs from `list_repos`. Use `[]` for conversational agents that do not touch code.\n - `db_configs: [db_id]` — real DB IDs from `list_db_configs`. Use `[]` if none.\n\n (If `can_create_agents` is false, still list the blocks and add a `status: CANNOT CREATE — creation disabled` line so the user can enable it or pre-select an existing agent.)\n\n## Flow\nClose with a fenced code block tagged `flow` showing the wiring as ASCII. Use the role/step name (not a fabricated step_id) and label the type. Example shape:\n\n```flow\nintake (agent: analyst)\n ↓\nroute (evaluator)\n ├─ a → process (llm)\n └─ b → fallback (human)\n ↓\n end (end)\n```\n\nKeep it scannable — one node per line, one arrow per edge, evaluator branches with `├─`/`└─`, convergence shown by sharing the next line. The user uses this diagram to sanity-check wiring before approval.\n\n## Open questions\nOnly include this section if something is genuinely ambiguous. One bullet per question.\n\n# Rules\n- Write plain markdown, no code fences around the whole thing (the `flow` block is the only fenced block).\n- If `review_feedback` is non-empty, treat the previous draft as a starting point and revise per the feedback — do not start from scratch unless the user asked you to.\n- Do NOT produce raw orchestration JSON here. This is the human-facing draft. The JSON is produced by the saver agent later.\n- Keep it concise — the user will read this.",
|
|
199
|
+
"prompt_template": "You are the Plan Drafter for the Synapse AI Builder. Produce a HUMAN-READABLE markdown draft of the orchestration plan. The user will read this next and either approve it or send revision feedback. After approval, a saver agent reads this draft to materialise the real orchestration JSON, so the draft must be precise enough to act on.\n\n# Inputs\nIntent: {state.intent}\n\nRequirements spec:\n{state.requirements}\n\nExisting orchestration (only on update; empty otherwise):\n{state.existing_orch}\n\nPre-selected agent IDs: {state.selected_agent_ids}\nCan create new agents: {state.can_create_agents}\n\nPrevious draft (empty on first pass):\n{state.plan_draft}\n\nUser's revision feedback on the previous draft (empty on first pass):\n{state.review_feedback}\n\n# Step-type palette (use these — never invent a type)\n{{STEP_TYPE_CHEATSHEET}}\n\n# What to write\nMarkdown with these sections, in this order:\n\n## Overview\nOne paragraph: what the orchestration does end-to-end. On update, call out what is changing vs the existing definition.\n\n## State schema\nBullet list of state keys with type and one-line purpose.\n\n## Steps\nNumbered list. For each step:\n- **Name** (step type: one of agent / llm / evaluator / human / parallel / merge / loop / transform / tool / end)\n- What it does, its input keys, its output key, and its next step (or route map for evaluators).\n- For agent steps: role name AND whether it maps to an existing agent (`agent_xxxxxxx`) or a NEW agent to create (describe its job + tools).\n- For tool steps: the forced tool name. If you are uncertain a tool exists, flag it under Open questions rather than guessing.\n- For human steps: the prompt the user will see and the fields collected.\n\n## Agents summary\nTwo short lists:\n- **Existing agents reused**: one line each — `role → agent_id (name)`.\n- **New agents to create**: one block per new agent. Each block uses this exact shape so the downstream Agent Creator can parse it deterministically:\n - `role: <role_label>` — short identifier used elsewhere in the plan (e.g. `question_generator`).\n - `name: <Display Name>` — what the agent will be called.\n - `type: conversational | code | orchestrator | delegate` — pick `code` ONLY if the agent reads/writes a repo; pick `orchestrator` only if it runs a sub-orchestration; pick `delegate` if the agent dynamically routes to sub-agents; everything else is `conversational`.\n - `delegate_agent_ids: [agent_id, ...]` — ONLY for delegate type: restrict which agents it can route to. Use `[]` to allow all agents.\n - `purpose: <one sentence>` — what this agent does end-to-end.\n - `tools: [tool_name, tool_name]` — narrow list, only what the role needs. Use real tool names (confirmed by the analyst via `get_tools_detail`). Never `[\"all\"]`.\n - `repos: [repo_id, repo_id]` — real repo IDs from `list_repos`. Use `[]` for conversational agents that do not touch code.\n - `db_configs: [db_id]` — real DB IDs from `list_db_configs`. Use `[]` if none.\n\n (If `can_create_agents` is false, still list the blocks and add a `status: CANNOT CREATE — creation disabled` line so the user can enable it or pre-select an existing agent.)\n\n## Flow\nClose with a fenced code block tagged `flow` showing the wiring as ASCII. Use the role/step name (not a fabricated step_id) and label the type. Example shape:\n\n```flow\nintake (agent: analyst)\n ↓\nroute (evaluator)\n ├─ a → process (llm)\n └─ b → fallback (human)\n ↓\n end (end)\n```\n\nKeep it scannable — one node per line, one arrow per edge, evaluator branches with `├─`/`└─`, convergence shown by sharing the next line. The user uses this diagram to sanity-check wiring before approval.\n\n## Open questions\nOnly include this section if something is genuinely ambiguous. One bullet per question.\n\n# Rules\n- Write plain markdown, no code fences around the whole thing (the `flow` block is the only fenced block).\n- If `review_feedback` is non-empty, treat the previous draft as a starting point and revise per the feedback — do not start from scratch unless the user asked you to.\n- Do NOT produce raw orchestration JSON here. This is the human-facing draft. The JSON is produced by the saver agent later.\n- Keep it concise — the user will read this.",
|
|
200
200
|
"route_map": {},
|
|
201
201
|
"route_descriptions": {},
|
|
202
202
|
"evaluator_prompt": null,
|
|
@@ -104,6 +104,7 @@ Before writing, reason through:
|
|
|
104
104
|
- `conversational` — multi-turn; handle context shifts and follow-ups
|
|
105
105
|
- `code` — precision required; read before write, cite paths/lines
|
|
106
106
|
- `orchestrator` — decompose tasks, manage sub-agent handoffs, synthesize results
|
|
107
|
+
- `delegate` — dynamic router; receives queries and routes to sub-agents via delegate_to_agent tool; focus on routing logic, clear task framing, and synthesizing results
|
|
107
108
|
- **Failure Modes:** Where will this agent most likely hallucinate, go off-scope, or stall?
|
|
108
109
|
|
|
109
110
|
━━━ PHASE 2: GENERATE THE SYSTEM PROMPT ━━━
|
|
@@ -284,6 +285,23 @@ async def generate_agent_prompt(req: GeneratePromptRequest):
|
|
|
284
285
|
f"---\n{req.existing_prompt.strip()}\n---"
|
|
285
286
|
)
|
|
286
287
|
|
|
288
|
+
# Build delegate sub-agents section (only for delegate-type agents)
|
|
289
|
+
delegates_section = ""
|
|
290
|
+
if req.agent_type == "delegate" and req.agents:
|
|
291
|
+
agent_lines = "\n".join(
|
|
292
|
+
f" - [{a.get('id', '')}] {a.get('name', '')} ({a.get('type', 'conversational')})"
|
|
293
|
+
+ (f": {a['description']}" if a.get('description') else "")
|
|
294
|
+
for a in req.agents
|
|
295
|
+
)
|
|
296
|
+
delegates_section = (
|
|
297
|
+
f"\n\n━━━ AVAILABLE SUB-AGENTS (delegation targets) ━━━\n"
|
|
298
|
+
f"This delegate agent can route tasks to the following sub-agents:\n"
|
|
299
|
+
f"{agent_lines}\n"
|
|
300
|
+
f"\nThe generated prompt should reference these agents by name where relevant, "
|
|
301
|
+
f"describe how to decide which agent to delegate to, and explain how to synthesize "
|
|
302
|
+
f"results when multiple agents are involved."
|
|
303
|
+
)
|
|
304
|
+
|
|
287
305
|
user_message = (
|
|
288
306
|
f"Current Date & Time: {current_datetime}\n\n"
|
|
289
307
|
f"━━━ AGENT TYPE ━━━\n"
|
|
@@ -295,6 +313,7 @@ async def generate_agent_prompt(req: GeneratePromptRequest):
|
|
|
295
313
|
f"What problem are they trying to solve? What would make this agent "
|
|
296
314
|
f"genuinely useful vs. just technically correct?"
|
|
297
315
|
f"{tools_section}"
|
|
316
|
+
f"{delegates_section}"
|
|
298
317
|
f"{existing_section}"
|
|
299
318
|
)
|
|
300
319
|
|
|
@@ -3,11 +3,16 @@ Repo management endpoints (CRUD + reindex).
|
|
|
3
3
|
"""
|
|
4
4
|
import os
|
|
5
5
|
import json
|
|
6
|
-
from fastapi import APIRouter, HTTPException, BackgroundTasks
|
|
6
|
+
from fastapi import APIRouter, HTTPException, BackgroundTasks, Body
|
|
7
|
+
from pydantic import BaseModel
|
|
7
8
|
from core.models import Repo
|
|
8
9
|
from core.config import DATA_DIR, load_settings
|
|
9
10
|
from core.json_store import JsonStore
|
|
10
11
|
|
|
12
|
+
|
|
13
|
+
class ReindexOptions(BaseModel):
|
|
14
|
+
full_reindex: bool = False
|
|
15
|
+
|
|
11
16
|
router = APIRouter()
|
|
12
17
|
|
|
13
18
|
_repos_store = JsonStore(os.path.join(DATA_DIR, "repos.json"))
|
|
@@ -147,7 +152,8 @@ async def delete_repo(repo_id: str):
|
|
|
147
152
|
return {"status": "success"}
|
|
148
153
|
|
|
149
154
|
@router.post("/api/repos/{repo_id}/reindex")
|
|
150
|
-
async def reindex_repo(repo_id: str, background_tasks: BackgroundTasks
|
|
155
|
+
async def reindex_repo(repo_id: str, background_tasks: BackgroundTasks,
|
|
156
|
+
opts: ReindexOptions = Body(default=ReindexOptions())):
|
|
151
157
|
repos = load_repos()
|
|
152
158
|
repo = next((r for r in repos if r["id"] == repo_id), None)
|
|
153
159
|
if not repo:
|
|
@@ -174,14 +180,16 @@ async def reindex_repo(repo_id: str, background_tasks: BackgroundTasks):
|
|
|
174
180
|
# Run in background
|
|
175
181
|
try:
|
|
176
182
|
from services.code_indexer import run_index
|
|
177
|
-
background_tasks.add_task(run_index, repo_id, real_path,
|
|
183
|
+
background_tasks.add_task(run_index, repo_id, real_path,
|
|
184
|
+
repo["included_patterns"], repo["excluded_patterns"],
|
|
185
|
+
opts.full_reindex)
|
|
178
186
|
except ImportError as e:
|
|
179
187
|
print("Indexer unavailable:", e)
|
|
180
188
|
repo["status"] = "error"
|
|
181
189
|
save_repos(repos)
|
|
182
190
|
raise HTTPException(status_code=500, detail="Indexer service not available")
|
|
183
191
|
|
|
184
|
-
return {"status": "indexing_started"}
|
|
192
|
+
return {"status": "indexing_started", "full_reindex": opts.full_reindex}
|
|
185
193
|
|
|
186
194
|
|
|
187
195
|
@router.post("/api/repos/{repo_id}/stop-index")
|
|
@@ -35,6 +35,21 @@ async def get_custom_tools():
|
|
|
35
35
|
return load_custom_tools()
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
_NATIVE_SERVER_LABELS: dict[str, str] = {
|
|
39
|
+
"code_vault_search": "Code Search",
|
|
40
|
+
"time": "Time & Date",
|
|
41
|
+
"sql": "SQL Database",
|
|
42
|
+
"personal_details": "Personal Details",
|
|
43
|
+
"collect_data": "Collect Data",
|
|
44
|
+
"pdf_parser": "PDF Parser",
|
|
45
|
+
"xlsx_parser": "Excel / XLSX",
|
|
46
|
+
"vault_sandbox": "Vault Sandbox",
|
|
47
|
+
"web_scraper": "Web Scraper",
|
|
48
|
+
"bash": "Bash",
|
|
49
|
+
"Filesystem": "Filesystem",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
38
53
|
@router.get("/api/tools/available")
|
|
39
54
|
async def get_available_tools():
|
|
40
55
|
"""List all available tools from all sources (Native Agents, External MCP, Custom HTTP)"""
|
|
@@ -54,7 +69,7 @@ async def get_available_tools():
|
|
|
54
69
|
cfg = _server.mcp_manager.get_server_config(server_name)
|
|
55
70
|
display_label = (cfg.get("label") or server_name) if cfg else server_name
|
|
56
71
|
else:
|
|
57
|
-
display_label = server_name
|
|
72
|
+
display_label = _NATIVE_SERVER_LABELS.get(server_name, server_name)
|
|
58
73
|
|
|
59
74
|
result = await session.list_tools()
|
|
60
75
|
for t in result.tools:
|
package/backend/core/server.py
CHANGED
|
@@ -189,7 +189,7 @@ def _build_native_mcp_servers() -> list[dict]:
|
|
|
189
189
|
servers.append({
|
|
190
190
|
"name": "Browser Automation",
|
|
191
191
|
"command": _NPX_CMD,
|
|
192
|
-
"args": ["-y", "@playwright/mcp@latest", "--browser", "
|
|
192
|
+
"args": ["-y", "@playwright/mcp@latest", "--browser", "chrome", "--output-dir", "data/vault/playwright"],
|
|
193
193
|
"env": env_dict,
|
|
194
194
|
})
|
|
195
195
|
|
package/backend/core/tools.py
CHANGED
|
@@ -29,6 +29,10 @@ DEFAULT_TOOLS_BY_TYPE = {
|
|
|
29
29
|
},
|
|
30
30
|
"code": {
|
|
31
31
|
"search_codebase",
|
|
32
|
+
"multi_repo_search",
|
|
33
|
+
"find_similar_code",
|
|
34
|
+
"list_indexed_files",
|
|
35
|
+
"get_file_chunks",
|
|
32
36
|
},
|
|
33
37
|
"orchestrator": set(), # orchestrator agents delegate to sub-agents; no extra tools needed
|
|
34
38
|
"delegate": set(), # delegate agents route to sub-agents via synthetic delegate_to_agent tool
|
|
@@ -90,10 +94,12 @@ async def aggregate_all_tools(agent_sessions, active_agent, custom_tools_list):
|
|
|
90
94
|
if tool_name not in allowed_tools:
|
|
91
95
|
allowed_tools.append(tool_name)
|
|
92
96
|
|
|
93
|
-
# Remove
|
|
97
|
+
# Remove embedding tools if embed_code is disabled
|
|
94
98
|
settings = load_settings()
|
|
95
99
|
if not settings.get("embed_code", False):
|
|
96
|
-
|
|
100
|
+
_embed_tools = {"search_codebase", "multi_repo_search", "find_similar_code",
|
|
101
|
+
"list_indexed_files", "get_file_chunks"}
|
|
102
|
+
allowed_tools = [t for t in allowed_tools if t not in _embed_tools]
|
|
97
103
|
|
|
98
104
|
# Standard MCP Tools
|
|
99
105
|
for session_name, session in agent_sessions.items():
|
|
@@ -207,6 +213,18 @@ def build_system_prompt(agent_system_template, tools_json, session_id, session_s
|
|
|
207
213
|
"""
|
|
208
214
|
# Determine if code embedding is enabled (for conditional tool description)
|
|
209
215
|
_embed_code = load_settings().get("embed_code", False)
|
|
216
|
+
_embed_tools_desc = (
|
|
217
|
+
"- **`search_codebase`** - semantic search within specific repos. Requires `repo_ids`."
|
|
218
|
+
" Add `file_filter` (e.g. `.py`, `components`) to narrow results.\n"
|
|
219
|
+
"- **`multi_repo_search`** - like search_codebase but `repo_ids` is optional;"
|
|
220
|
+
" omit to search ALL indexed repos at once.\n"
|
|
221
|
+
"- **`find_similar_code`** - pass a code snippet to find similar patterns across repos"
|
|
222
|
+
" (vs. natural language in search_codebase).\n"
|
|
223
|
+
"- **`list_indexed_files`** - list every file in the embedding index with chunk counts."
|
|
224
|
+
" Use before searching to understand coverage.\n"
|
|
225
|
+
"- **`get_file_chunks`** - retrieve all indexed chunks for a specific file"
|
|
226
|
+
" (the semantic outline). Use after finding a relevant file."
|
|
227
|
+
) if _embed_code else ""
|
|
210
228
|
|
|
211
229
|
# Get current date/time for context injection
|
|
212
230
|
now = datetime.datetime.now(zoneinfo.ZoneInfo("UTC"))
|
|
@@ -279,7 +297,7 @@ You have access to the following tools:
|
|
|
279
297
|
{tools_json}
|
|
280
298
|
|
|
281
299
|
**CODE & FILE NAVIGATION:**
|
|
282
|
-
{
|
|
300
|
+
{_embed_tools_desc}
|
|
283
301
|
- **`grep`** — search for a pattern inside a file or across all files in a folder. Pass a file path to search that file, or a folder path to search all files within it. Use `file_pattern` to filter by extension (e.g. `*.py`, `*.ts`).
|
|
284
302
|
- **`glob`** — discover file paths by pattern (e.g. `**/*.py`, `src/**/*.ts`).
|
|
285
303
|
- **`read_file`** — read an entire file. Use when you already know the path and the file is small. For large files, prefer `read_file_by_lines` or `grep`.
|
|
@@ -356,6 +356,31 @@ def get_index_status(repo_id: str) -> dict:
|
|
|
356
356
|
return {"status": "error", "message": str(e), "count": 0}
|
|
357
357
|
|
|
358
358
|
|
|
359
|
+
def _get_current_vector_dim(repo_id: str) -> int | None:
|
|
360
|
+
"""Return the vector column dimension currently in the DB, or None if absent."""
|
|
361
|
+
if not COCOINDEX_AVAILABLE:
|
|
362
|
+
return None
|
|
363
|
+
table_name = get_table_name(repo_id)
|
|
364
|
+
db_url = _get_db_url()
|
|
365
|
+
if not db_url:
|
|
366
|
+
return None
|
|
367
|
+
try:
|
|
368
|
+
with psycopg.connect(db_url) as conn:
|
|
369
|
+
with conn.cursor() as cur:
|
|
370
|
+
cur.execute("""
|
|
371
|
+
SELECT atttypmod
|
|
372
|
+
FROM pg_attribute
|
|
373
|
+
JOIN pg_class ON pg_class.oid = pg_attribute.attrelid
|
|
374
|
+
WHERE pg_class.relname = %s
|
|
375
|
+
AND pg_attribute.attname = 'embedding'
|
|
376
|
+
AND atttypmod > 0
|
|
377
|
+
""", (table_name,))
|
|
378
|
+
row = cur.fetchone()
|
|
379
|
+
return row[0] if row else None
|
|
380
|
+
except Exception:
|
|
381
|
+
return None
|
|
382
|
+
|
|
383
|
+
|
|
359
384
|
def drop_index(repo_id: str):
|
|
360
385
|
"""Drop all tables and CocoIndex metadata for a repo — ensures clean rebuild."""
|
|
361
386
|
if not COCOINDEX_AVAILABLE:
|
|
@@ -399,7 +424,7 @@ def _update_repo_status(repo_id: str, **fields):
|
|
|
399
424
|
json.dump(repos, f, indent=4)
|
|
400
425
|
|
|
401
426
|
|
|
402
|
-
def run_index_task(repo_id: str, repo_path: str, included_patterns: list[str], excluded_patterns: list[str]):
|
|
427
|
+
def run_index_task(repo_id: str, repo_path: str, included_patterns: list[str], excluded_patterns: list[str], full_reindex: bool = True):
|
|
403
428
|
if not COCOINDEX_AVAILABLE:
|
|
404
429
|
msg = (
|
|
405
430
|
"CocoIndex not installed in the backend venv — indexing skipped.\n"
|
|
@@ -416,11 +441,31 @@ def run_index_task(repo_id: str, repo_path: str, included_patterns: list[str], e
|
|
|
416
441
|
stop = _stop_events.setdefault(repo_id, threading.Event())
|
|
417
442
|
stop.clear() # reset from any previous stop request
|
|
418
443
|
|
|
419
|
-
print(f"Starting index builder for {repo_id}...")
|
|
444
|
+
print(f"Starting index builder for {repo_id} (full_reindex={full_reindex})...")
|
|
420
445
|
_update_repo_status(repo_id, status="indexing", error_message=None)
|
|
421
446
|
try:
|
|
422
|
-
|
|
423
|
-
|
|
447
|
+
if full_reindex:
|
|
448
|
+
print("[index] Step 0: drop stale tables + CocoIndex metadata")
|
|
449
|
+
drop_index(repo_id)
|
|
450
|
+
else:
|
|
451
|
+
# Schema guard: if the embedding dim stored in the DB differs from the currently
|
|
452
|
+
# configured model's dim, a full rebuild is unavoidable (vector columns are fixed-width).
|
|
453
|
+
try:
|
|
454
|
+
model = get_configured_embedding_model()
|
|
455
|
+
settings = load_settings()
|
|
456
|
+
dim = probe_embedding_dim(model, settings)
|
|
457
|
+
current_dim = _get_current_vector_dim(repo_id)
|
|
458
|
+
if current_dim is not None and current_dim != dim:
|
|
459
|
+
print(f"[index] Embedding dim changed ({current_dim} → {dim}), promoting to full reindex")
|
|
460
|
+
drop_index(repo_id)
|
|
461
|
+
full_reindex = True
|
|
462
|
+
else:
|
|
463
|
+
print("[index] Incremental reindex — tracking table preserved, only changed files will be processed")
|
|
464
|
+
except Exception as e:
|
|
465
|
+
print(f"[index] Schema check failed ({e}), falling back to full reindex")
|
|
466
|
+
drop_index(repo_id)
|
|
467
|
+
full_reindex = True
|
|
468
|
+
|
|
424
469
|
if stop.is_set():
|
|
425
470
|
print(f"[index] Stop requested after step 0 — aborting {repo_id}")
|
|
426
471
|
_update_repo_status(repo_id, status="stopped", error_message=None)
|
|
@@ -451,7 +496,10 @@ def run_index_task(repo_id: str, repo_path: str, included_patterns: list[str], e
|
|
|
451
496
|
# update() is a long-running Rust call — we can't interrupt it mid-way,
|
|
452
497
|
# but we check the stop flag immediately after it returns.
|
|
453
498
|
print("[index] Step 4: repo_flow.update()")
|
|
454
|
-
|
|
499
|
+
if full_reindex:
|
|
500
|
+
repo_flow.update(full_reprocess=True)
|
|
501
|
+
else:
|
|
502
|
+
repo_flow.update() # incremental — CocoIndex processes only changed/new files
|
|
455
503
|
|
|
456
504
|
if stop.is_set():
|
|
457
505
|
print(f"[index] Stop requested — marking {repo_id} as stopped")
|
|
@@ -493,10 +541,10 @@ def stop_index(repo_id: str) -> bool:
|
|
|
493
541
|
return False
|
|
494
542
|
|
|
495
543
|
|
|
496
|
-
def run_index(repo_id: str, repo_path: str, included_patterns: list[str], excluded_patterns: list[str]):
|
|
544
|
+
def run_index(repo_id: str, repo_path: str, included_patterns: list[str], excluded_patterns: list[str], full_reindex: bool = True):
|
|
497
545
|
t = threading.Thread(
|
|
498
546
|
target=run_index_task,
|
|
499
|
-
args=(repo_id, repo_path, included_patterns, excluded_patterns),
|
|
547
|
+
args=(repo_id, repo_path, included_patterns, excluded_patterns, full_reindex),
|
|
500
548
|
daemon=True,
|
|
501
549
|
)
|
|
502
550
|
_active_threads[repo_id] = t
|