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
4 changes: 2 additions & 2 deletions .vitepress/theme/BlogPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ function shareUrl(platform) {
<LinkIcon :size="14" />
{{ copied ? 'Copied!' : 'Copy link' }}
</button>
<a class="blog-share-btn" :href="shareUrl('twitter')" target="_blank" rel="noopener" aria-label="Share on X (Twitter)">
<a class="blog-share-btn" :href="shareUrl('twitter')" target="_blank" rel="noopener noreferrer" aria-label="Share on X (Twitter)">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path :d="xTwitterPath"/></svg>
Share
</a>
<a class="blog-share-btn" :href="shareUrl('linkedin')" target="_blank" rel="noopener" aria-label="Share on LinkedIn">
<a class="blog-share-btn" :href="shareUrl('linkedin')" target="_blank" rel="noopener noreferrer" aria-label="Share on LinkedIn">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path :d="linkedInPath"/></svg>
Share
</a>
Expand Down
23 changes: 22 additions & 1 deletion .vitepress/theme/Breadcrumb.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { computed } from 'vue'
import { computed, watchEffect, onUnmounted } from 'vue'
import { useRoute, useData } from 'vitepress'

const route = useRoute()
Expand Down Expand Up @@ -41,6 +41,27 @@ const breadcrumb = computed(() => {
if (!label) return null
return { label, link: firstPageMap[section] || `/${section}/` }
})

// Inject BreadcrumbList JSON-LD for search engines
let scriptEl = null
watchEffect(() => {
if (typeof document === 'undefined') return
if (scriptEl) { scriptEl.remove(); scriptEl = null }
if (!breadcrumb.value) return
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Docs', item: 'https://runcycles.io/' },
{ '@type': 'ListItem', position: 2, name: breadcrumb.value.label, item: `https://runcycles.io${breadcrumb.value.link}` },
],
}
scriptEl = document.createElement('script')
scriptEl.type = 'application/ld+json'
scriptEl.textContent = JSON.stringify(jsonLd)
document.head.appendChild(scriptEl)
})
onUnmounted(() => { if (scriptEl) scriptEl.remove() })
</script>

<template>
Expand Down
34 changes: 34 additions & 0 deletions .vitepress/theme/HomeCodeSnippet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import { createHighlighter } from 'shiki'

const activeTab = ref('python')
const highlighted = ref({})
const copied = ref(false)

function copyCode() {
const code = snippets[activeTab.value]?.code
if (!code || typeof navigator === 'undefined') return
navigator.clipboard.writeText(code)
copied.value = true
setTimeout(() => { copied.value = false }, 2000)
}

const tabs = [
{ key: 'python', label: 'Python' },
Expand Down Expand Up @@ -162,6 +171,9 @@ onMounted(async () => {
</button>
</div>
<div class="code-block">
<button class="copy-btn" @click="copyCode" :aria-label="copied ? 'Copied' : 'Copy code'">
{{ copied ? 'Copied!' : 'Copy' }}
</button>
<div v-if="highlighted[activeTab]" v-html="highlighted[activeTab]" />
<pre v-else><code>{{ snippets[activeTab].code }}</code></pre>
</div>
Expand Down Expand Up @@ -266,6 +278,7 @@ onMounted(async () => {
}

.code-block {
position: relative;
background: var(--vp-code-block-bg);
padding: 20px 24px;
overflow-x: auto;
Expand All @@ -274,6 +287,27 @@ onMounted(async () => {
overflow-y: auto;
}

.copy-btn {
position: absolute;
top: 12px;
right: 12px;
padding: 4px 12px;
font-size: 12px;
font-family: var(--vp-font-family-base);
color: var(--vp-c-text-3);
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
cursor: pointer;
z-index: 1;
transition: color 0.2s, border-color 0.2s;
}

.copy-btn:hover {
border-color: var(--vp-c-brand-1);
color: var(--vp-c-brand-1);
}

.code-block :deep(pre) {
margin: 0;
background: transparent !important;
Expand Down
12 changes: 12 additions & 0 deletions .vitepress/theme/PageFeedback.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ function vote(value) {
try {
localStorage.setItem(storageKey.value, value)
} catch {}
// Send feedback beacon — works with any analytics endpoint.
// Set window.__FEEDBACK_URL to enable (e.g. in a VitePress head script).
try {
const url = typeof window !== 'undefined' && window.__FEEDBACK_URL
if (url) {
navigator.sendBeacon(url, JSON.stringify({
page: route.path,
helpful: value === 'yes',
ts: Date.now(),
}))
}
} catch {}
}
</script>

Expand Down
12 changes: 12 additions & 0 deletions .vitepress/theme/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,18 @@
border-radius: 4px;
}

/* ── Reduced motion ── */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

/* ── Mobile responsive ── */
@media (max-width: 640px) {
.blog-card {
Expand Down
2 changes: 1 addition & 1 deletion how-to/how-to-add-budget-control-to-a-langchain-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LangChain makes it easy to build agents that call LLMs, search the web, execute

That's fine when you're experimenting. It's a real problem when you're running agents in production — especially across multiple users or tenants. A single misbehaving agent loop can burn through hundreds of dollars before anyone notices.

This guide shows how to add per-run budget control to a LangChain agent using [Cycles](https://runcycles.com) — without rewriting your agent logic.
This guide shows how to add per-run budget control to a LangChain agent using [Cycles](https://runcycles.io) — without rewriting your agent logic.

::: tip Already using the callback handler?
If you want per-LLM-call budget tracking (a reservation around every model invocation), see [Integrating Cycles with LangChain](/how-to/integrating-cycles-with-langchain). This guide covers a different pattern: a **single reservation around the entire agent run**, plus optional tool-level checks.
Expand Down
Loading