Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions docs/interactive-capabilities/capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"title": "OpenBitFun Playbook",
"origin": "https://playbook.openbitfun.com",
"source": "src/shared/interactive-capabilities/catalog.json",
"digest": "5c26d781f664b1daa3cef9062f0ad3e776544242b80fbd1fc303d59d4494eed3",
"ownerDigest": "0b2d30952efd57108d9e566dc0bf5a176f2b3d753abfb736bfc32b2c1fa3f7b7",
"digest": "513e184cc2d93f183cdea258516f532caf58ac6400ef76dce9b54f6de0752627",
"ownerDigest": "3cc6d7d869b2c90c2161494a854b5ff7eb72ea69a1a28e40ccd42065fb3382e2",
"searchAcceptance": [
{
"id": "native-image-generation",
Expand Down Expand Up @@ -16923,7 +16923,8 @@
"type": "string",
"enum": [
"native",
"ptc"
"ptc",
"ptc_python"
]
},
"outputSchema": {
Expand Down Expand Up @@ -30162,8 +30163,8 @@
},
{
"id": "tool-presentation",
"titleZh": "选择模型使用原生模式还是 PTC TypeScript 模式",
"titleEn": "Choose native mode or PTC TypeScript mode for the model",
"titleZh": "选择模型使用原生模式、PTC TypeScript 或 PTC Python 模式",
"titleEn": "Choose native, PTC TypeScript, or PTC Python mode for the model",
"destination": {
"kind": "settings",
"pageId": "tools.execution",
Expand Down Expand Up @@ -30359,13 +30360,14 @@
"id": "tool-presentation-mode",
"titleZh": "工具呈现模式",
"titleEn": "Tool presentation mode",
"descriptionZh": "选择模型直接调用原生工具,或通过 PTC TypeScript 调用工具。",
"descriptionEn": "Choose whether the model calls native tools directly or uses PTC TypeScript.",
"descriptionZh": "选择模型直接调用原生工具,或通过 PTC TypeScript/Python 调用工具。",
"descriptionEn": "Choose whether the model calls native tools directly or uses PTC TypeScript or Python.",
"valueSchema": {
"type": "string",
"enum": [
"native",
"ptc"
"ptc",
"ptc_python"
]
}
},
Expand Down Expand Up @@ -30496,8 +30498,8 @@
"Review, revoke, or clear remembered project permission grants and audit records",
"按需延迟加载工具定义以减少智能体初始上下文",
"Deferred tool loading on demand to reduce initial agent context",
"选择模型使用原生模式还是 PTC TypeScript 模式",
"Choose native mode or PTC TypeScript mode for the model",
"选择模型使用原生模式、PTC TypeScript 或 PTC Python 模式",
"Choose native, PTC TypeScript, or PTC Python mode for the model",
"设置子智能体与 Swarm 最大并发及安全、强制并行或串行策略",
"Set subagent and swarm concurrency plus safe-only, forced-parallel, or serial policy",
"设置或取消单次工具调用超时",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Manage agent tool permissions, presentation mode, concurrency, timeouts, deferre
- Review, revoke, or clear remembered project permission grants and audit records
- **智能体可直接控制 / Direct Agent control** · 按需延迟加载工具定义以减少智能体初始上下文
- Deferred tool loading on demand to reduce initial agent context
- **智能体可直接控制 / Direct Agent control** · 选择模型使用原生模式还是 PTC TypeScript 模式
- Choose native mode or PTC TypeScript mode for the model
- **智能体可直接控制 / Direct Agent control** · 选择模型使用原生模式、PTC TypeScript 或 PTC Python 模式
- Choose native, PTC TypeScript, or PTC Python mode for the model
- **智能体可直接控制 / Direct Agent control** · 设置子智能体与 Swarm 最大并发及安全、强制并行或串行策略
- Set subagent and swarm concurrency plus safe-only, forced-parallel, or serial policy
- **智能体可直接控制 / Direct Agent control** · 设置或取消单次工具调用超时
Expand Down Expand Up @@ -69,7 +69,7 @@ Manage agent tool permissions, presentation mode, concurrency, timeouts, deferre
| --- | --- | --- | --- |
| 显示权限模式选择器 / Show permission-mode selector | `boolean` | 在聊天输入框下方显示或隐藏权限模式快捷选择器。 | Show or hide the permission-mode shortcut below the chat composer. |
| 延迟加载工具 / Deferred tool loading | `boolean` | 按需加载大型工具定义,减少智能体初始上下文。 | Load large tool definitions on demand to reduce initial agent context. |
| 工具呈现模式 / Tool presentation mode | `native` / `ptc` | 选择模型直接调用原生工具,或通过 PTC TypeScript 调用工具。 | Choose whether the model calls native tools directly or uses PTC TypeScript. |
| 工具呈现模式 / Tool presentation mode | `native` / `ptc` / `ptc_python` | 选择模型直接调用原生工具,或通过 PTC TypeScript/Python 调用工具。 | Choose whether the model calls native tools directly or uses PTC TypeScript or Python. |
| 子智能体批量执行策略 / Subagent batch policy | `safe_only` / `force_parallel` / `serial` | 选择仅安全任务并行、强制并行或串行执行。 | Choose safe-only parallelism, forced parallelism, or serial execution. |
| 子智能体最大并发 / Maximum subagent concurrency | `integer` (1–32) | 限制同时运行的子智能体数量。 | Limit the number of subagents that may run at once. |
| Swarm 最大并发 / Maximum swarm concurrency | `integer` (1–64) | 限制 Swarm 中同时执行的工作单元。 | Limit concurrent work units inside a swarm. |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
"catalogDigest": "5c26d781f664b1daa3cef9062f0ad3e776544242b80fbd1fc303d59d4494eed3",
"catalogDigest": "513e184cc2d93f183cdea258516f532caf58ac6400ef76dce9b54f6de0752627",
"count": 204,
"reasonCounts": {
"externalAuth": 4,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schemaVersion": 2,
"generatedFrom": "src/shared/interactive-capabilities/catalog.json",
"catalogDigest": "5c26d781f664b1daa3cef9062f0ad3e776544242b80fbd1fc303d59d4494eed3",
"catalogDigest": "513e184cc2d93f183cdea258516f532caf58ac6400ef76dce9b54f6de0752627",
"commandCount": 709,
"coverage": {
"commandCount": 709,
Expand Down
2 changes: 1 addition & 1 deletion scripts/core-boundaries/rules/feature-rules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ export const optionalDependencyFeatureOwnerRules = [
{ depName: 'openbitfun-agent-workflows', ownerFeatures: ['deep-research'] },
{
depName: 'openbitfun-core-types',
ownerFeatures: ['deep-research', 'remote-connect', 'remote-ssh-concrete', 'speech'],
ownerFeatures: ['deep-research', 'ptc-runtime', 'remote-connect', 'remote-ssh-concrete', 'speech'],
},
{ depName: 'openbitfun-product-domains', ownerFeatures: ['account-identity', 'canvas-runtime', 'function-agents', 'hook-import', 'miniapp-market', 'miniapp-runtime', 'miniapp-storage', 'plugin-source', 'remote-connect'] },
{ depName: 'openbitfun-runtime-ports', ownerFeatures: ['deep-research', 'git', 'ptc-runtime', 'remote-connect', 'remote-ssh', 'remote-ssh-concrete', 'script-tool-runtime', 'web-tools'] },
Expand Down
22 changes: 21 additions & 1 deletion src/crates/assembly/core/src/agentic/coordination/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ use openbitfun_agent_runtime::remote_file_delivery::{
};
use openbitfun_agent_runtime::sdk::PermissionReply;
use openbitfun_agent_runtime::user_questions::USER_INPUT_AVAILABLE_CONTEXT_KEY;
use openbitfun_agent_tools::{PTC_TOOL_PRESENTATION_CONTEXT_KEY, PTC_TOOL_PRESENTATION_MODE};
use openbitfun_agent_tools::{
PTC_LANGUAGE_CONTEXT_KEY, PTC_TOOL_PRESENTATION_CONTEXT_KEY, PTC_TOOL_PRESENTATION_MODE,
};
use openbitfun_config_contracts::model_pool::AgentModelSelection;
use openbitfun_config_contracts::model_pool::AgentModelSelections;
use openbitfun_core_types::model_pool::ModelSelection;
Expand Down Expand Up @@ -7339,6 +7341,15 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
PTC_TOOL_PRESENTATION_CONTEXT_KEY.to_string(),
PTC_TOOL_PRESENTATION_MODE.to_string(),
);
context_vars.insert(
PTC_LANGUAGE_CONTEXT_KEY.to_string(),
session
.config
.tool_presentation_mode
.language()
.as_str()
.to_string(),
);
}
let review_agent = is_review_agent_type(&effective_agent_type);
let turn_review_manifest =
Expand Down Expand Up @@ -7951,6 +7962,15 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
PTC_TOOL_PRESENTATION_CONTEXT_KEY.to_string(),
PTC_TOOL_PRESENTATION_MODE.to_string(),
);
context_vars.insert(
PTC_LANGUAGE_CONTEXT_KEY.to_string(),
session
.config
.tool_presentation_mode
.language()
.as_str()
.to_string(),
);
}
if let Some(user_input_available) = metadata_bool(
plan.user_message_metadata.as_ref(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,25 @@ mod tests {
.expect("tool presentation mode is config-backed");
assert_eq!(applied.changed_path, "ai.tool_presentation_mode");
assert_eq!(applied.effective_value, Value::String("ptc".to_string()));

let applied_python = configure_config_backed_option(
&service,
option,
&Value::String("ptc_python".to_string()),
)
.await
.expect("PTC Python should be accepted")
.expect("tool presentation mode is config-backed");
assert_eq!(
applied_python.effective_value,
Value::String("ptc_python".to_string())
);
assert_eq!(
read_config_backed_option(&service, option)
.await
.expect("PTC Python should be readable"),
Some(Value::String("ptc_python".to_string()))
);
}

#[tokio::test]
Expand Down
116 changes: 100 additions & 16 deletions src/crates/assembly/core/src/agentic/tools/pipeline/tool_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ use openbitfun_agent_tools::{
build_tool_execution_timeout_presentation,
build_user_rejected_tool_presentation_with_instruction,
build_user_steering_interrupted_presentation, build_write_tail_closure_notice,
render_ptc_loaded_tool_typescript_sdk, render_tool_result_for_assistant,
render_ptc_loaded_tool_sdk, render_tool_result_for_assistant,
validate_tool_execution_admission, DynamicToolInfo, LoadedDeferredToolSpec, PermissionIntent,
PtcToolContract, ResolvedToolInvocation, ToolExecutionAdmissionRejection,
ToolExecutionAdmissionRequest, ToolExecutionErrorPresentation, CALL_DEFERRED_TOOL_NAME,
GET_TOOL_SPEC_TOOL_NAME, PTC_NESTED_ALLOWED_TOOLS_CONTEXT_KEY,
GET_TOOL_SPEC_TOOL_NAME, PTC_LANGUAGE_CONTEXT_KEY, PTC_NESTED_ALLOWED_TOOLS_CONTEXT_KEY,
USER_STEERING_INTERRUPTED_MESSAGE,
};
#[cfg(feature = "ptc-runtime")]
use openbitfun_core_types::PtcLanguage;
use openbitfun_runtime_ports::{
PermissionReply, PermissionRequest, PermissionRequestSource, PermissionRequestSourceKind,
PermissionResourceCaseSensitivity, RoundInjectionToolPreemption,
Expand All @@ -50,6 +52,8 @@ use openbitfun_runtime_ports::{
};
#[cfg(feature = "ptc-runtime")]
use openbitfun_services_integrations::ptc_runtime::NodePtcRuntime;
#[cfg(feature = "ptc-runtime")]
use openbitfun_services_integrations::python_ptc_runtime::PythonPtcRuntime;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::time::{Instant, SystemTime};
Expand Down Expand Up @@ -183,9 +187,13 @@ fn convert_tool_result_with_metadata(
// "completed successfully" can hide fields the model needs for the
// next decision.
let assistant_text = result_for_assistant.or_else(|| {
let mut assistant_visible_data = assistant_data.clone();
if let Some(object) = assistant_visible_data.as_object_mut() {
object.remove("__ptc_language");
}
Some(render_tool_result_for_assistant(
effective_tool_name,
&assistant_data,
&assistant_visible_data,
))
});
// Tools with a typed response envelope can report a recoverable
Expand Down Expand Up @@ -754,6 +762,14 @@ struct PtcPipelineToolCallHandler {
loaded_deferred_tool_specs: Arc<TokioMutex<Vec<LoadedDeferredToolSpec>>>,
}

#[cfg(feature = "ptc-runtime")]
fn build_ptc_tool_spec_response(language: PtcLanguage, sdk_source: String) -> serde_json::Value {
serde_json::json!({
"language": language.as_str(),
"sdk_source": sdk_source,
})
}

#[cfg(feature = "ptc-runtime")]
#[async_trait::async_trait]
impl PtcToolCallHandler for PtcPipelineToolCallHandler {
Expand Down Expand Up @@ -886,12 +902,20 @@ impl PtcToolCallHandler for PtcPipelineToolCallHandler {
.cloned()
.unwrap_or_else(|| serde_json::json!({}));
let output_schema = tool.output_schema();
let typescript_sdk = render_ptc_loaded_tool_typescript_sdk(&PtcToolContract::new(
tool_name.clone(),
description,
input_schema,
output_schema,
));
let language = if self
.context
.context_vars
.get(PTC_LANGUAGE_CONTEXT_KEY)
.is_some_and(|language| language.eq_ignore_ascii_case("python"))
{
PtcLanguage::Python
} else {
PtcLanguage::TypeScript
};
let sdk_source = render_ptc_loaded_tool_sdk(
&PtcToolContract::new(tool_name.clone(), description, input_schema, output_schema),
language,
);

let mut loaded = self.loaded_deferred_tool_specs.lock().await;
if let Some(existing) = loaded.iter_mut().find(|spec| spec.tool_name == tool_name) {
Expand All @@ -902,9 +926,7 @@ impl PtcToolCallHandler for PtcPipelineToolCallHandler {
catalog_generation,
});
}
Ok(serde_json::json!({
"typescript_sdk": typescript_sdk,
}))
Ok(build_ptc_tool_spec_response(language, sdk_source))
}
}

Expand Down Expand Up @@ -2974,7 +2996,12 @@ impl ToolPipeline {
.effective_arguments()
.get("timeout_ms")
.and_then(serde_json::Value::as_u64);
let runtime = if context.is_remote() {
let use_python = context
.custom_data
.get(PTC_LANGUAGE_CONTEXT_KEY)
.and_then(serde_json::Value::as_str)
.is_some_and(|language| language.eq_ignore_ascii_case("python"));
let runtime: Box<dyn PtcRuntime> = if context.is_remote() {
#[cfg(feature = "ssh-remote")]
{
let workspace = context.workspace.as_ref().ok_or_else(|| {
Expand Down Expand Up @@ -3002,7 +3029,11 @@ impl ToolPipeline {
"Remote SSH services are not initialized".to_string(),
)
})?;
NodePtcRuntime::for_remote(ssh_manager, connection_id)
if use_python {
Box::new(PythonPtcRuntime::for_remote(ssh_manager, connection_id))
} else {
Box::new(NodePtcRuntime::for_remote(ssh_manager, connection_id))
}
}
#[cfg(not(feature = "ssh-remote"))]
{
Expand All @@ -3011,7 +3042,11 @@ impl ToolPipeline {
));
}
} else {
NodePtcRuntime::discover()
if use_python {
Box::new(PythonPtcRuntime::discover())
} else {
Box::new(NodePtcRuntime::discover())
}
};
let operation_id = task.tool_call.tool_id.clone();
let handler = Arc::new(PtcPipelineToolCallHandler {
Expand Down Expand Up @@ -3055,6 +3090,34 @@ impl ToolPipeline {
"logs": response.logs,
})
};
// Persist the source language alongside the result so replayed RunCode
// cards can select the correct syntax highlighter even though the
// provider's original arguments only contain `code`.
let ptc_language = context
.custom_data
.get(PTC_LANGUAGE_CONTEXT_KEY)
.map(|value| {
if value
.as_str()
.is_some_and(|value| value.eq_ignore_ascii_case("python"))
{
PtcLanguage::Python
} else {
PtcLanguage::TypeScript
}
})
.unwrap_or_default();
if let Some(object) = data.as_object_mut() {
object.insert(
"__ptc_language".to_string(),
serde_json::Value::String(ptc_language.as_str().to_string()),
);
} else {
data = serde_json::json!({
"value": data,
"__ptc_language": ptc_language.as_str(),
});
}
let loaded_deferred_tool_specs = handler.loaded_deferred_tool_specs.lock().await.clone();
if !loaded_deferred_tool_specs.is_empty() {
let loaded_specs_value = serde_json::to_value(&loaded_deferred_tool_specs)
Expand Down Expand Up @@ -4359,6 +4422,23 @@ mod tests {
}));
}

#[cfg(feature = "ptc-runtime")]
#[test]
fn ptc_tool_spec_response_uses_one_language_neutral_sdk_field() {
for language in [PtcLanguage::TypeScript, PtcLanguage::Python] {
let response = build_ptc_tool_spec_response(language, "sdk".to_string());
assert_eq!(
response,
json!({
"language": language.as_str(),
"sdk_source": "sdk",
})
);
assert!(response.get("typescript_sdk").is_none());
assert!(response.get("python_sdk").is_none());
}
}

#[cfg(feature = "ptc-runtime")]
#[tokio::test]
async fn ptc_run_code_dispatches_nested_calls_through_the_pipeline() {
Expand Down Expand Up @@ -4396,7 +4476,11 @@ mod tests {
results[0].tool_name,
openbitfun_agent_tools::PTC_RUN_CODE_TOOL_NAME
);
assert_eq!(results[0].result.result, json!({"content": "ok"}));
assert_eq!(results[0].result.result["content"], json!("ok"));
assert_eq!(
results[0].result.result["__ptc_language"],
json!("typescript")
);

let nested = pipeline
.state_manager
Expand Down
Loading
Loading