feat(mobile): add repo context support and streaming
- Add repoContext parameter to Gateway agent method - Update AgentParamsSchema to include repoContext (owner/name/branch) - Add repoContext to AgentCommandOpts type - Pass repoContext through gateway to agent command - Fix streaming implementation with proper enum usage (MessageRole, ToolCallStatus) - Add disabled prop to MessageInputView - Clean up lint issues (remove unused imports) The mobile app can now send repository context (owner/repo/branch) when starting a coding session. The gateway will receive this context and pass it to the agent command, preparing for workspace clone/checkout implementation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a591c51010
commit
175c7a0cbc
@ -8,9 +8,12 @@ interface Props {
|
|||||||
placeholder: string
|
placeholder: string
|
||||||
onChangeText: (text: string) => void
|
onChangeText: (text: string) => void
|
||||||
onSend: () => void
|
onSend: () => void
|
||||||
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const MessageInputView: React.FC<Props> = ({ text, placeholder, onChangeText, onSend }) => {
|
const MessageInputView: React.FC<Props> = ({ text, placeholder, onChangeText, onSend, disabled = false }) => {
|
||||||
|
const isSendDisabled = disabled || !text.trim()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.inputWrapper}>
|
<View style={styles.inputWrapper}>
|
||||||
@ -22,11 +25,12 @@ const MessageInputView: React.FC<Props> = ({ text, placeholder, onChangeText, on
|
|||||||
placeholderTextColor={Colors.secondaryText}
|
placeholderTextColor={Colors.secondaryText}
|
||||||
multiline
|
multiline
|
||||||
maxLength={2000}
|
maxLength={2000}
|
||||||
|
editable={!disabled}
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.sendButton, { opacity: text.trim() ? 1 : 0.5 }]}
|
style={[styles.sendButton, { opacity: isSendDisabled ? 0.5 : 1 }]}
|
||||||
onPress={onSend}
|
onPress={onSend}
|
||||||
disabled={!text.trim()}
|
disabled={isSendDisabled}
|
||||||
>
|
>
|
||||||
<Ionicons name="arrow-up" size={20} color={Colors.buttonPrimaryText} />
|
<Ionicons name="arrow-up" size={20} color={Colors.buttonPrimaryText} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { View, Text, ScrollView, StyleSheet } from 'react-native'
|
import { View, Text, StyleSheet } from 'react-native'
|
||||||
import { Colors, Spacing, Radius } from '../theme/colors'
|
import { Colors, Spacing } from '../theme/colors'
|
||||||
import { Message } from '../models/types'
|
import { Message } from '../models/types'
|
||||||
import ToolCallView from './ToolCallView'
|
import ToolCallView from './ToolCallView'
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import {
|
|||||||
allModels,
|
allModels,
|
||||||
} from '../models/types'
|
} from '../models/types'
|
||||||
import MessageInputView from './MessageInputView'
|
import MessageInputView from './MessageInputView'
|
||||||
import Chip from './Chip'
|
|
||||||
import { useGitHubRepos, type GitHubRepo, type GitHubBranch } from '../hooks/useGitHub'
|
import { useGitHubRepos, type GitHubRepo, type GitHubBranch } from '../hooks/useGitHub'
|
||||||
import { useSettings } from '../hooks/useSettings'
|
import { useSettings } from '../hooks/useSettings'
|
||||||
import { GitHubAPI } from '../services/github'
|
import { GitHubAPI } from '../services/github'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||||
|
|
||||||
const SETTINGS_KEY = '@clawdbot_settings'
|
const SETTINGS_KEY = '@clawdbot_settings'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react'
|
import React, { useState, useEffect, useRef, useCallback } from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
Text,
|
Text,
|
||||||
@ -8,46 +8,200 @@ import {
|
|||||||
KeyboardAvoidingView,
|
KeyboardAvoidingView,
|
||||||
Platform,
|
Platform,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
|
ActivityIndicator,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { Ionicons } from '@expo/vector-icons'
|
import { Ionicons } from '@expo/vector-icons'
|
||||||
import { useAppState } from '../contexts/AppContext'
|
import { useAppState } from '../contexts/AppContext'
|
||||||
import { Session, getFullName } from '../models/types'
|
import { Session, getFullName, Message, ToolCall, MessageRole, ToolCallStatus } from '../models/types'
|
||||||
import { Colors, Spacing, Radius } from '../theme/colors'
|
import { Colors, Spacing, Radius } from '../theme/colors'
|
||||||
import MessageView from '../components/MessageView'
|
import MessageView from '../components/MessageView'
|
||||||
import MessageInputView from '../components/MessageInputView'
|
import MessageInputView from '../components/MessageInputView'
|
||||||
import Chip from '../components/Chip'
|
import Chip from '../components/Chip'
|
||||||
|
import { useGateway, type ToolCallEvent } from '../hooks/useGateway'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
session: Session
|
session: Session
|
||||||
onBack: () => void
|
onBack: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In-memory messages for this session (not persisted to AppContext)
|
||||||
|
const createMessage = (): Message => ({
|
||||||
|
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
||||||
|
role: MessageRole.Assistant,
|
||||||
|
content: '',
|
||||||
|
timestamp: new Date(),
|
||||||
|
toolCalls: [],
|
||||||
|
})
|
||||||
|
|
||||||
const ChatView: React.FC<Props> = ({ session, onBack }) => {
|
const ChatView: React.FC<Props> = ({ session, onBack }) => {
|
||||||
const { sessions, sendMessage } = useAppState()
|
const { sessions } = useAppState()
|
||||||
const [messageText, setMessageText] = useState('')
|
const [messageText, setMessageText] = useState('')
|
||||||
const [showCreatePR, setShowCreatePR] = useState(false)
|
const [showCreatePR, setShowCreatePR] = useState(false)
|
||||||
|
const [messages, setMessages] = useState<Message[]>([])
|
||||||
|
const [pendingToolCalls, setPendingToolCalls] = useState<Map<string, ToolCall>>(new Map())
|
||||||
|
const [isRunning, setIsRunning] = useState(false)
|
||||||
|
|
||||||
const scrollViewRef = useRef<ScrollView>(null)
|
const scrollViewRef = useRef<ScrollView>(null)
|
||||||
|
|
||||||
// Get current session from state to see updates
|
// Get current session from state
|
||||||
const currentSession = sessions.find((s) => s.id === session.id) || session
|
const currentSession = sessions.find((s) => s.id === session.id) || session
|
||||||
|
|
||||||
const hasToolCalls = currentSession.messages.some((m) => m.toolCalls.length > 0)
|
// Gateway hooks
|
||||||
|
const { connected: gatewayConnected, sendMessage: sendGatewayMessage, onToolCall, onAssistant, onLifecycle } = useGateway()
|
||||||
|
|
||||||
const handleSendMessage = () => {
|
// Handle tool call events
|
||||||
if (messageText.trim()) {
|
useEffect(() => {
|
||||||
sendMessage(messageText, currentSession)
|
const unsubscribe = onToolCall((event: ToolCallEvent) => {
|
||||||
setMessageText('')
|
const { toolCallId, name, phase, args, partialResult, result, isError } = event
|
||||||
|
|
||||||
|
setPendingToolCalls((prev) => {
|
||||||
|
const next = new Map(prev)
|
||||||
|
|
||||||
|
if (phase === 'start') {
|
||||||
|
const toolCall: ToolCall = {
|
||||||
|
id: toolCallId,
|
||||||
|
type: name as any,
|
||||||
|
name,
|
||||||
|
input: JSON.stringify(args || {}),
|
||||||
|
status: ToolCallStatus.Running,
|
||||||
|
}
|
||||||
|
next.set(toolCallId, toolCall)
|
||||||
|
|
||||||
|
// Add to current assistant message
|
||||||
|
setMessages((prevMsgs) => {
|
||||||
|
const updated = [...prevMsgs]
|
||||||
|
const lastMsg = updated[updated.length - 1]
|
||||||
|
if (lastMsg?.role === MessageRole.Assistant) {
|
||||||
|
lastMsg.toolCalls = [...lastMsg.toolCalls, toolCall]
|
||||||
|
}
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
} else if (phase === 'update') {
|
||||||
|
const existing = next.get(toolCallId)
|
||||||
|
if (existing) {
|
||||||
|
existing.output = partialResult || ''
|
||||||
|
}
|
||||||
|
} else if (phase === 'end') {
|
||||||
|
const existing = next.get(toolCallId)
|
||||||
|
if (existing) {
|
||||||
|
existing.status = isError ? ToolCallStatus.Failed : ToolCallStatus.Completed
|
||||||
|
existing.output = result ? JSON.stringify(result, null, 2) : existing.output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
|
||||||
|
// Trigger scroll
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollViewRef.current?.scrollToEnd({ animated: true })
|
||||||
|
}, 50)
|
||||||
|
})
|
||||||
|
|
||||||
|
return unsubscribe
|
||||||
|
}, [onToolCall])
|
||||||
|
|
||||||
|
// Handle assistant events (text streaming)
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = onAssistant((event) => {
|
||||||
|
const { delta } = event
|
||||||
|
|
||||||
|
setMessages((prev) => {
|
||||||
|
const updated = [...prev]
|
||||||
|
let lastMsg = updated[updated.length - 1]
|
||||||
|
|
||||||
|
// Create new message if none exists or last is from user
|
||||||
|
if (!lastMsg || lastMsg.role !== MessageRole.Assistant) {
|
||||||
|
lastMsg = createMessage()
|
||||||
|
updated.push(lastMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta) {
|
||||||
|
lastMsg.content += delta
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
|
||||||
|
// Trigger scroll
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollViewRef.current?.scrollToEnd({ animated: true })
|
||||||
|
}, 50)
|
||||||
|
})
|
||||||
|
|
||||||
|
return unsubscribe
|
||||||
|
}, [onAssistant])
|
||||||
|
|
||||||
|
// Handle lifecycle events
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = onLifecycle((event) => {
|
||||||
|
const { msg, phase } = event as { msg?: string; phase?: string }
|
||||||
|
|
||||||
|
if (phase === 'start') {
|
||||||
|
setIsRunning(true)
|
||||||
|
// Create new assistant message for this run
|
||||||
|
setMessages((prev) => [...prev, createMessage()])
|
||||||
|
} else if (phase === 'end' || phase === 'error') {
|
||||||
|
setIsRunning(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg) {
|
||||||
|
console.log('[Agent]', msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return unsubscribe
|
||||||
|
}, [onLifecycle])
|
||||||
|
|
||||||
|
const handleSendMessage = async () => {
|
||||||
|
if (!messageText.trim()) return
|
||||||
|
|
||||||
|
const userMsg: Message = {
|
||||||
|
id: `msg-${Date.now()}-user`,
|
||||||
|
role: MessageRole.User,
|
||||||
|
content: messageText,
|
||||||
|
timestamp: new Date(),
|
||||||
|
toolCalls: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
setMessages((prev) => [...prev, userMsg])
|
||||||
|
const textToSend = messageText
|
||||||
|
setMessageText('')
|
||||||
|
|
||||||
|
// Scroll to show user message
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollViewRef.current?.scrollToEnd({ animated: true })
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
// Send to gateway
|
||||||
|
const result = await sendGatewayMessage(textToSend, {
|
||||||
|
owner: currentSession.repository.owner,
|
||||||
|
name: currentSession.repository.name,
|
||||||
|
branch: currentSession.repository.defaultBranch,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
// Failed to send - show error
|
||||||
|
setMessages((prev) => {
|
||||||
|
const errorMsg: Message = {
|
||||||
|
id: `msg-${Date.now()}-error`,
|
||||||
|
role: MessageRole.Assistant,
|
||||||
|
content: 'Failed to connect to clawdbot gateway. Please check your settings.',
|
||||||
|
timestamp: new Date(),
|
||||||
|
toolCalls: [],
|
||||||
|
}
|
||||||
|
return [...prev, errorMsg]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto scroll to bottom when messages change
|
// Combine session messages with live messages
|
||||||
useEffect(() => {
|
const allMessages = [...currentSession.messages, ...messages]
|
||||||
if (scrollViewRef.current) {
|
const hasToolCalls = allMessages.some((m) => m.toolCalls.length > 0)
|
||||||
setTimeout(() => {
|
|
||||||
scrollViewRef.current?.scrollToEnd({ animated: true })
|
// Connection status indicator
|
||||||
}, 100)
|
const connectionStatus = gatewayConnected ? 'Connected' : 'Disconnected'
|
||||||
}
|
const connectionColor = gatewayConnected ? Colors.success : Colors.error
|
||||||
}, [currentSession.messages.length])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
@ -63,9 +217,14 @@ const ChatView: React.FC<Props> = ({ session, onBack }) => {
|
|||||||
? currentSession.title.slice(0, 30) + '...'
|
? currentSession.title.slice(0, 30) + '...'
|
||||||
: currentSession.title}
|
: currentSession.title}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.headerSubtitle}>
|
<View style={styles.headerSubtitleRow}>
|
||||||
{getFullName(currentSession.repository)} · Default
|
<Text style={styles.headerSubtitle}>
|
||||||
</Text>
|
{getFullName(currentSession.repository)} · {currentSession.repository.defaultBranch}
|
||||||
|
</Text>
|
||||||
|
{isRunning && (
|
||||||
|
<ActivityIndicator size="small" color={Colors.accent} style={styles.spinner} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<TouchableOpacity style={styles.menuButton}>
|
<TouchableOpacity style={styles.menuButton}>
|
||||||
@ -73,6 +232,14 @@ const ChatView: React.FC<Props> = ({ session, onBack }) => {
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* Connection status bar */}
|
||||||
|
<View style={[styles.connectionBar, { backgroundColor: connectionColor + '20' }]}>
|
||||||
|
<View style={[styles.connectionDot, { backgroundColor: connectionColor }]} />
|
||||||
|
<Text style={[styles.connectionText, { color: connectionColor }]}>
|
||||||
|
Gateway: {connectionStatus}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
{/* Messages + Input with keyboard avoidance */}
|
{/* Messages + Input with keyboard avoidance */}
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={styles.keyboardAvoidingView}
|
style={styles.keyboardAvoidingView}
|
||||||
@ -85,15 +252,18 @@ const ChatView: React.FC<Props> = ({ session, onBack }) => {
|
|||||||
contentContainerStyle={styles.messagesContainer}
|
contentContainerStyle={styles.messagesContainer}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
>
|
>
|
||||||
{currentSession.messages.map((message) => (
|
{allMessages.map((message, index) => (
|
||||||
<MessageView key={message.id} message={message} />
|
<MessageView
|
||||||
|
key={`${message.id}-${index}`}
|
||||||
|
message={message}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Create PR button */}
|
{/* Create PR button */}
|
||||||
{hasToolCalls && (
|
{hasToolCalls && (
|
||||||
<View style={styles.prButtonContainer}>
|
<View style={styles.prButtonContainer}>
|
||||||
<Text style={styles.branchName} numberOfLines={1}>
|
<Text style={styles.branchName} numberOfLines={1}>
|
||||||
claude/add-popular-tweets-dy04J
|
{currentSession.repository.owner}/{currentSession.repository.name}
|
||||||
</Text>
|
</Text>
|
||||||
<TouchableOpacity style={styles.createPRButton} onPress={() => setShowCreatePR(true)}>
|
<TouchableOpacity style={styles.createPRButton} onPress={() => setShowCreatePR(true)}>
|
||||||
<Text style={styles.createPRText}>Create PR</Text>
|
<Text style={styles.createPRText}>Create PR</Text>
|
||||||
@ -111,16 +281,23 @@ const ChatView: React.FC<Props> = ({ session, onBack }) => {
|
|||||||
placeholder="Add feedback..."
|
placeholder="Add feedback..."
|
||||||
onChangeText={setMessageText}
|
onChangeText={setMessageText}
|
||||||
onSend={handleSendMessage}
|
onSend={handleSendMessage}
|
||||||
|
disabled={isRunning}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Bottom chips */}
|
{/* Bottom chips */}
|
||||||
<View style={styles.chipsContainer}>
|
<View style={styles.chipsContainer}>
|
||||||
<Chip icon="code-working" text="Branch" secondaryText="claude/add-popular-tweets..." />
|
<Chip
|
||||||
<TouchableOpacity style={styles.createPRChip} onPress={() => setShowCreatePR(true)}>
|
icon="code-working"
|
||||||
<Text style={styles.chipText}>Create PR</Text>
|
text="Branch"
|
||||||
<Ionicons name="open-outline" size={12} color={Colors.primaryText} />
|
secondaryText={currentSession.repository.defaultBranch}
|
||||||
<Ionicons name="ellipsis-horizontal" size={12} color={Colors.primaryText} />
|
/>
|
||||||
</TouchableOpacity>
|
{hasToolCalls && (
|
||||||
|
<TouchableOpacity style={styles.createPRChip} onPress={() => setShowCreatePR(true)}>
|
||||||
|
<Text style={styles.chipText}>Create PR</Text>
|
||||||
|
<Ionicons name="open-outline" size={12} color={Colors.primaryText} />
|
||||||
|
<Ionicons name="ellipsis-horizontal" size={12} color={Colors.primaryText} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
@ -154,14 +331,37 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
color: Colors.primaryText,
|
color: Colors.primaryText,
|
||||||
},
|
},
|
||||||
|
headerSubtitleRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
headerSubtitle: {
|
headerSubtitle: {
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.secondaryText,
|
color: Colors.secondaryText,
|
||||||
},
|
},
|
||||||
|
spinner: {
|
||||||
|
marginLeft: Spacing.XS,
|
||||||
|
},
|
||||||
menuButton: {
|
menuButton: {
|
||||||
width: 24,
|
width: 24,
|
||||||
height: 24,
|
height: 24,
|
||||||
},
|
},
|
||||||
|
connectionBar: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingHorizontal: Spacing.MD,
|
||||||
|
paddingVertical: Spacing.XS,
|
||||||
|
gap: Spacing.XS,
|
||||||
|
},
|
||||||
|
connectionDot: {
|
||||||
|
width: 6,
|
||||||
|
height: 6,
|
||||||
|
borderRadius: 3,
|
||||||
|
},
|
||||||
|
connectionText: {
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
keyboardAvoidingView: {
|
keyboardAvoidingView: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,14 +4,12 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
Pressable,
|
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { Ionicons } from '@expo/vector-icons'
|
import { Ionicons } from '@expo/vector-icons'
|
||||||
import { useAppState, Session } from '../contexts/AppContext'
|
import { useAppState, Session } from '../contexts/AppContext'
|
||||||
import { Colors, Spacing, Radius } from '../theme/colors'
|
import { Colors, Spacing, Radius } from '../theme/colors'
|
||||||
import { getFullName } from '../models/types'
|
|
||||||
import SessionRow from '../components/SessionRow'
|
import SessionRow from '../components/SessionRow'
|
||||||
import NewSessionSheet from '../components/NewSessionSheet'
|
import NewSessionSheet from '../components/NewSessionSheet'
|
||||||
|
|
||||||
|
|||||||
@ -63,4 +63,10 @@ export type AgentCommandOpts = {
|
|||||||
extraSystemPrompt?: string;
|
extraSystemPrompt?: string;
|
||||||
/** Per-call stream param overrides (best-effort). */
|
/** Per-call stream param overrides (best-effort). */
|
||||||
streamParams?: AgentStreamParams;
|
streamParams?: AgentStreamParams;
|
||||||
|
/** Repository context for GitHub workspace management. */
|
||||||
|
repoContext?: {
|
||||||
|
owner: string;
|
||||||
|
name: string;
|
||||||
|
branch: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -64,6 +64,13 @@ export const AgentParamsSchema = Type.Object(
|
|||||||
idempotencyKey: NonEmptyString,
|
idempotencyKey: NonEmptyString,
|
||||||
label: Type.Optional(SessionLabelString),
|
label: Type.Optional(SessionLabelString),
|
||||||
spawnedBy: Type.Optional(Type.String()),
|
spawnedBy: Type.Optional(Type.String()),
|
||||||
|
repoContext: Type.Optional(
|
||||||
|
Type.Object({
|
||||||
|
owner: NonEmptyString,
|
||||||
|
name: NonEmptyString,
|
||||||
|
branch: NonEmptyString,
|
||||||
|
}),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{ additionalProperties: false },
|
{ additionalProperties: false },
|
||||||
);
|
);
|
||||||
|
|||||||
@ -82,6 +82,11 @@ export const agentHandlers: GatewayRequestHandlers = {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
label?: string;
|
label?: string;
|
||||||
spawnedBy?: string;
|
spawnedBy?: string;
|
||||||
|
repoContext?: {
|
||||||
|
owner: string;
|
||||||
|
name: string;
|
||||||
|
branch: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
const cfg = loadConfig();
|
const cfg = loadConfig();
|
||||||
const idem = request.idempotencyKey;
|
const idem = request.idempotencyKey;
|
||||||
@ -334,6 +339,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
|||||||
runId,
|
runId,
|
||||||
lane: request.lane,
|
lane: request.lane,
|
||||||
extraSystemPrompt: request.extraSystemPrompt,
|
extraSystemPrompt: request.extraSystemPrompt,
|
||||||
|
repoContext: request.repoContext,
|
||||||
},
|
},
|
||||||
defaultRuntime,
|
defaultRuntime,
|
||||||
context.deps,
|
context.deps,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user