-
Notifications
You must be signed in to change notification settings - Fork 1k
[KYUUBI #7379][4/4] Data Agent Engine: REST API, SSE streaming, and Web UI #7431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2bdda7f
6b5438e
a6386e3
a3787c3
ff08fa9
c303511
988b09f
37f5d96
1ffd925
f5ed9eb
7a8d44d
755aa61
6aee3a9
277c094
2ed1e14
845acc8
e7c440b
ab6d0ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,3 +26,4 @@ Quick Start | |
| quick_start | ||
| quick_start_with_helm | ||
| quick_start_with_jdbc | ||
| quick_start_with_data_agent | ||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,18 +118,46 @@ private static DataSource attachJdbcDataSource( | |
| if (jdbcUrl == null) { | ||
| return null; | ||
| } | ||
| LOG.info("Data Agent JDBC URL configured ({})", jdbcUrl.replaceAll("//.*@", "//<redacted>@")); | ||
|
|
||
| String sessionUser = | ||
| ConfUtils.optionalString(conf, KyuubiReservedKeys.KYUUBI_SESSION_USER_KEY()); | ||
| JdbcDialect dialect = JdbcDialect.fromUrl(jdbcUrl); | ||
| if (dialect == null) { | ||
| throw new IllegalArgumentException( | ||
| "Invalid " + KyuubiConf.ENGINE_DATA_AGENT_JDBC_URL().key()); | ||
| } | ||
| LOG.info("Data Agent JDBC datasource configured ({})", dialect.datasourceName()); | ||
|
|
||
| // For Kyuubi/HiveServer2 backends, pass the session user for proxy-user impersonation — | ||
| // but only when the URL does not already carry explicit credentials, because URL-supplied | ||
| // credentials should win (some users pass credentials via session variables). | ||
| String subprotocol = JdbcDialect.extractSubprotocol(jdbcUrl); | ||
| boolean isKyuubiBackend = "kyuubi".equals(subprotocol) || "hive2".equals(subprotocol); | ||
| String hikariUser = null; | ||
| if (isKyuubiBackend && !hasKyuubiUrlCredentials(jdbcUrl)) { | ||
| hikariUser = ConfUtils.optionalString(conf, KyuubiReservedKeys.KYUUBI_SESSION_USER_KEY()); | ||
| } | ||
|
|
||
| DataSource ds = DataSourceFactory.create(jdbcUrl, sessionUser); | ||
| DataSource ds = DataSourceFactory.create(jdbcUrl, hikariUser); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for kerberized cases, the engine process runs under kyuubi server's host and same user, then the super user's TGT (allows proxying any users) is visible to this process, so this would lead to arbitrary user impersonation |
||
| registry.register(new RunSelectQueryTool(ds, queryTimeoutSeconds)); | ||
| registry.register(new RunMutationQueryTool(ds, queryTimeoutSeconds)); | ||
| promptBuilder.datasource(JdbcDialect.fromUrl(jdbcUrl).datasourceName()); | ||
| promptBuilder.datasource(dialect.datasourceName()); | ||
| return ds; | ||
| } | ||
|
|
||
| /** | ||
| * Return true when a Kyuubi/HiveServer2 JDBC URL carries an explicit user identity as the | ||
| * semicolon-delimited {@code ;user=...} session variable. Only semicolon parameters are checked | ||
| * because the Kyuubi/Hive JDBC driver reads them as auth session vars — query parameters ({@code | ||
| * ?key=val}) are parsed as Hive configuration, not authentication. A URL that only carries {@code | ||
| * ;password=} without a user is not considered credentialed, so the session user is still passed | ||
| * for proxy-user impersonation. | ||
| */ | ||
| static boolean hasKyuubiUrlCredentials(String jdbcUrl) { | ||
| if (jdbcUrl == null) { | ||
| return false; | ||
| } | ||
| String lower = jdbcUrl.toLowerCase(); | ||
| return lower.contains(";user="); | ||
| } | ||
|
|
||
| @Override | ||
| public void open(String sessionId, String user) { | ||
| sessions.put(sessionId, new ConversationMemory()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.kyuubi.engine.dataagent.runtime.event; | ||
|
|
||
| /** | ||
| * A chunk of the LLM's hidden reasoning / chain-of-thought stream. Emitted alongside {@link | ||
| * ContentDelta} when the provider exposes a {@code reasoning_content} delta field (e.g. qwen3, | ||
| * DeepSeek-R1). UI clients typically render these in a collapsible "thinking" panel. | ||
| */ | ||
| public final class ReasoningDelta extends AgentEvent { | ||
| private final String text; | ||
|
|
||
| public ReasoningDelta(String text) { | ||
| super(EventType.REASONING_DELTA); | ||
| this.text = text; | ||
| } | ||
|
|
||
| public String text() { | ||
| return text; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| String preview = text != null && text.length() > 200 ? text.substring(0, 200) + "..." : text; | ||
| return "ReasoningDelta{text='" + preview + "'}"; | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.