{"id":706354,"date":"2026-05-11T10:13:17","date_gmt":"2026-05-11T09:13:17","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=ai&#038;p=706354"},"modified":"2026-05-11T10:13:20","modified_gmt":"2026-05-11T09:13:20","slug":"notre-orientation-pour-2026-workflows-d-ia-et-workflows-classiques-dans-les-jetbrains-ides","status":"publish","type":"ai","link":"https:\/\/blog.jetbrains.com\/fr\/ai\/2026\/05\/notre-orientation-pour-2026-workflows-d-ia-et-workflows-classiques-dans-les-jetbrains-ides\/","title":{"rendered":"Notre orientation pour 2026 : workflows d&#8217;IA et workflows classiques dans les JetBrains IDEs"},"content":{"rendered":"\n<p><strong>Deux mani\u00e8res valides d&#8217;\u00e9crire du code. Un m\u00eame endroit pour le faire.<\/strong><\/p>\n\n\n\n<div class=\"jb-quick-controls\" data-jb-quick-controls>\n  <p>\n    <strong>Version rapide pour les lecteurs fatigu\u00e9s par les actualit\u00e9s sur l&#8217;IA :<\/strong>\n    <button type=\"button\" class=\"jb-quick-toggle\" aria-pressed=\"false\">cliquez ici<\/button>\n    <span class=\"jb-quick-status\" aria-live=\"polite\"><\/span>\n  <\/p>\n<\/div>\n\n<style>\n  .jb-quick-controls {\n    display: none;\n    margin: 0 0 1em;\n  }\n\n  .jb-quick-controls.jb-quick-ready {\n    display: block;\n  }\n\n  .jb-quick-controls p {\n    margin: 0 0 1em;\n  }\n\n  .jb-quick-controls button {\n    -webkit-appearance: none;\n    appearance: none;\n    border: 0;\n    background: none;\n    padding: 0;\n    margin: 0 0 0 .25em;\n    color: inherit;\n    font: inherit;\n    cursor: pointer;\n    text-decoration: underline;\n    text-underline-offset: .12em;\n  }\n\n  .jb-quick-controls .jb-quick-toggle {\n    position: relative;\n    display: inline-block;\n    color: #6B57FF;\n    text-decoration: none;\n    box-shadow: inset 0 -1px 0 currentColor;\n  }\n\n  .jb-quick-controls .jb-quick-toggle:hover {\n    box-shadow: inset 0 -2px 0 currentColor;\n  }\n\n  .jb-quick-controls[data-jb-mode=\"short\"] .jb-quick-toggle {\n    color: #19191C;\n    background-image: none;\n    -webkit-text-fill-color: currentColor;\n    box-shadow: inset 0 -1px 0 currentColor;\n    animation: none;\n  }\n\n  .jb-quick-controls[data-jb-mode=\"short\"] .jb-quick-toggle::after {\n    display: none;\n  }\n\n  .jb-quick-controls button:focus {\n    outline: 2px solid currentColor;\n    outline-offset: 2px;\n  }\n\n  .jb-quick-controls .jb-quick-status {\n    margin-left: .5em;\n    opacity: .7;\n    font-size: .95em;\n  }\n\n  .jb-quick-hide {\n    overflow: hidden;\n  }\n\n  .jb-matrix-host {\n    position: fixed;\n    left: 0;\n    top: 0;\n    width: 0;\n    height: 0;\n    overflow: visible;\n    pointer-events: none;\n    z-index: 2147483000;\n  }\n\n  .jb-matrix-wrap {\n    position: fixed;\n    box-sizing: border-box;\n    margin: 0;\n    padding: 0;\n    overflow: visible;\n    pointer-events: none;\n    z-index: 1;\n    color: inherit;\n    -webkit-transform: translateZ(0);\n    transform: translateZ(0);\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n    contain: layout style paint;\n  }\n\n  .jb-matrix-wrap > * {\n    margin-top: 0 !important;\n    margin-bottom: 0 !important;\n  }\n\n  .jb-matrix-wrap.jb-matrix-active {\n    animation-name: jbMatrixBlockOut;\n    animation-duration: 980ms;\n    animation-timing-function: cubic-bezier(.2, .72, .22, 1);\n    animation-fill-mode: forwards;\n  }\n\n  @keyframes jbMatrixBlockOut {\n    0% {\n      opacity: 1;\n      transform: translate3d(0, 0, 0);\n    }\n    35% {\n      opacity: .94;\n      transform: translate3d(0, 0, 0);\n    }\n    72% {\n      opacity: .74;\n      transform: translate3d(0, 4px, 0);\n    }\n    100% {\n      opacity: 0;\n      transform: translate3d(0, 14px, 0);\n    }\n  }\n\n  @keyframes jbQuickGradientShift {\n    0% {\n      background-position: 0% 50%;\n    }\n\n    50% {\n      background-position: 100% 50%;\n    }\n\n    100% {\n      background-position: 0% 50%;\n    }\n  }\n\n  @supports ((-webkit-background-clip: text) or (background-clip: text)) {\n    .jb-quick-controls .jb-quick-toggle {\n      background-image: linear-gradient(90deg, #6B57FF 0%, #00A3FF 28%, #39CC8F 55%, #FF7A00 78%, #6B57FF 100%);\n      background-size: 260% 100%;\n      background-position: 0% 50%;\n      -webkit-background-clip: text;\n      background-clip: text;\n      -webkit-text-fill-color: transparent;\n      box-shadow: none;\n      animation: jbQuickGradientShift 9s ease-in-out infinite;\n    }\n\n    .jb-quick-controls .jb-quick-toggle::after {\n      content: '';\n      position: absolute;\n      left: 0;\n      right: 0;\n      bottom: .05em;\n      height: 1px;\n      background-image: linear-gradient(90deg, #6B57FF 0%, #00A3FF 28%, #39CC8F 55%, #FF7A00 78%, #6B57FF 100%);\n      background-size: 260% 100%;\n      background-position: 0% 50%;\n      animation: jbQuickGradientShift 9s ease-in-out infinite;\n      opacity: .95;\n    }\n\n    .jb-quick-controls .jb-quick-toggle:hover::after {\n      height: 2px;\n    }\n  }\n<\/style>\n\n<script>\n(function () {\n  function ready(fn) {\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', fn);\n    } else {\n      fn();\n    }\n  }\n\n  function toArray(list) {\n    if (list) {\n      return Array.prototype.slice.call(list);\n    }\n    return [];\n  }\n\n  function findAncestorByClass(node, className) {\n    while (node) {\n      if (node === document.body) {\n        break;\n      }\n\n      if (node.classList) {\n        if (node.classList.contains(className)) {\n          return node;\n        }\n      }\n\n      node = node.parentNode;\n    }\n\n    return null;\n  }\n\n  function isSupported() {\n    if (!document.querySelector) {\n      return false;\n    }\n\n    if (!document.addEventListener) {\n      return false;\n    }\n\n    if (!window.requestAnimationFrame) {\n      return false;\n    }\n\n    if (!window.getComputedStyle) {\n      return false;\n    }\n\n    if (!document.body) {\n      return false;\n    }\n\n    var styleProbe = document.createElement('span').style;\n    var hasTransform = false;\n    var hasAnimation = false;\n\n    if (typeof styleProbe.transform !== 'undefined') {\n      hasTransform = true;\n    } else {\n      if (typeof styleProbe.webkitTransform !== 'undefined') {\n        hasTransform = true;\n      }\n    }\n\n    if (typeof styleProbe.animationName !== 'undefined') {\n      hasAnimation = true;\n    } else {\n      if (typeof styleProbe.webkitAnimationName !== 'undefined') {\n        hasAnimation = true;\n      }\n    }\n\n    if (!hasTransform) {\n      return false;\n    }\n\n    if (!hasAnimation) {\n      return false;\n    }\n\n    return true;\n  }\n\n  function prefersReducedMotion() {\n    var result = false;\n\n    try {\n      if (window.matchMedia) {\n        result = !!window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n      }\n    } catch (error) {\n      result = false;\n    }\n\n    return result;\n  }\n\n  function isRectOnScreen(rect) {\n    if (rect.bottom <= -40) {\n      return false;\n    }\n\n    if (rect.top >= window.innerHeight + 40) {\n      return false;\n    }\n\n    if (rect.right <= -40) {\n      return false;\n    }\n\n    if (rect.left >= window.innerWidth + 40) {\n      return false;\n    }\n\n    return true;\n  }\n\n  function removeUiNoise(node) {\n    if (!node) {\n      return;\n    }\n\n    if (node.nodeType !== 1) {\n      return;\n    }\n\n    if (node.removeAttribute) {\n      node.removeAttribute('id');\n      node.removeAttribute('aria-describedby');\n      node.removeAttribute('aria-labelledby');\n    }\n\n    var selectors = [\n      'script',\n      'style',\n      'noscript',\n      'button',\n      '.copy-button',\n      '.sr-only',\n      '[aria-hidden=\"true\"]'\n    ];\n\n    var i;\n    for (i = 0; i < selectors.length; i += 1) {\n      var matches = node.querySelectorAll(selectors[i]);\n      var j;\n\n      for (j = matches.length - 1; j >= 0; j -= 1) {\n        var currentMatch = matches[j];\n\n        if (currentMatch) {\n          if (currentMatch.parentNode) {\n            currentMatch.parentNode.removeChild(currentMatch);\n          }\n        }\n      }\n    }\n\n    var descendants = node.getElementsByTagName('*');\n    for (i = 0; i < descendants.length; i += 1) {\n      descendants[i].removeAttribute('id');\n      descendants[i].removeAttribute('aria-describedby');\n      descendants[i].removeAttribute('aria-labelledby');\n    }\n  }\n\n  function copyBoxTextStyle(source, target) {\n    var computed = window.getComputedStyle(source);\n    var props = [\n      'fontFamily',\n      'fontSize',\n      'fontStyle',\n      'fontWeight',\n      'lineHeight',\n      'letterSpacing',\n      'textAlign',\n      'textTransform',\n      'color',\n      'paddingTop',\n      'paddingRight',\n      'paddingBottom',\n      'paddingLeft',\n      'listStyleType',\n      'listStylePosition'\n    ];\n    var i;\n\n    for (i = 0; i < props.length; i += 1) {\n      try {\n        target.style[props[i]] = computed[props[i]];\n      } catch (error) {}\n    }\n\n    target.style.marginTop = '0px';\n    target.style.marginBottom = '0px';\n  }\n\n  function cleanText(text) {\n    var value = text ? text : '';\n    value = value.replace(\/Copy heading link\/g, ' ');\n    value = value.replace(\/\\s+\/g, ' ');\n    value = value.replace(\/^\\s+\/, '');\n    value = value.replace(\/\\s+$\/, '');\n    return value;\n  }\n\n  function shouldSkipTextWalkElement(node) {\n    if (!node) {\n      return true;\n    }\n\n    if (node.nodeType !== 1) {\n      return false;\n    }\n\n    var tag = node.tagName;\n    if (tag === 'SCRIPT') {\n      return true;\n    }\n    if (tag === 'STYLE') {\n      return true;\n    }\n    if (tag === 'NOSCRIPT') {\n      return true;\n    }\n    if (tag === 'BUTTON') {\n      return true;\n    }\n\n    return false;\n  }\n\n  function collectTextNodes(root, maxCharacters) {\n    var items = [];\n    var total = 0;\n\n    function walk(node) {\n      if (total >= maxCharacters) {\n        return;\n      }\n\n      if (!node) {\n        return;\n      }\n\n      if (node.nodeType === 3) {\n        var value = node.nodeValue;\n        if (value) {\n          if (\/\\S\/.test(value)) {\n            items.push({ node: node, original: value });\n            total += value.length;\n          }\n        }\n        return;\n      }\n\n      if (shouldSkipTextWalkElement(node)) {\n        return;\n      }\n\n      var child = node.firstChild;\n      while (child) {\n        walk(child);\n        if (total >= maxCharacters) {\n          break;\n        }\n        child = child.nextSibling;\n      }\n    }\n\n    walk(root);\n    return items;\n  }\n\n  function scrambleValue(value, progress) {\n    var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%*+-\/=';\n    var keepRatio = progress * progress;\n    var output = '';\n    var i;\n\n    for (i = 0; i < value.length; i += 1) {\n      var ch = value.charAt(i);\n\n      if (\/\\s\/.test(ch)) {\n        output += ch;\n      } else {\n        if (Math.random() < keepRatio) {\n          output += ch;\n        } else {\n          output += chars.charAt(Math.floor(Math.random() * chars.length));\n        }\n      }\n    }\n\n    return output;\n  }\n\n  function runMatrixTextPass(root) {\n    var items = collectTextNodes(root, 1400);\n    var startTime = 0;\n    var duration = 680;\n    var lastUpdate = 0;\n\n    function tick(now) {\n      var i;\n\n      if (!startTime) {\n        startTime = now;\n      }\n\n      var elapsed = now - startTime;\n      var progress = elapsed \/ duration;\n\n      if (progress > 1) {\n        progress = 1;\n      }\n\n      if (now - lastUpdate > 36) {\n        lastUpdate = now;\n        for (i = 0; i < items.length; i += 1) {\n          items[i].node.nodeValue = scrambleValue(items[i].original, progress);\n        }\n      }\n\n      if (progress < 1) {\n        if (root.parentNode) {\n          requestAnimationFrame(tick);\n        }\n      } else {\n        for (i = 0; i < items.length; i += 1) {\n          items[i].node.nodeValue = items[i].original;\n        }\n      }\n    }\n\n    requestAnimationFrame(tick);\n  }\n\n  function buildFixedCloneFromElement(element, host) {\n    var rect = element.getBoundingClientRect();\n\n    if (!isRectOnScreen(rect)) {\n      return null;\n    }\n\n    if (rect.width < 12) {\n      return null;\n    }\n\n    if (rect.height < 8) {\n      return null;\n    }\n\n    var wrapper = document.createElement('div');\n    wrapper.className = 'jb-matrix-wrap';\n    wrapper._jbSourceElement = element;\n    wrapper.setAttribute('aria-hidden', 'true');\n    wrapper.style.left = rect.left + 'px';\n    wrapper.style.top = rect.top + 'px';\n    wrapper.style.width = rect.width + 'px';\n    wrapper.style.minHeight = rect.height + 'px';\n\n    var computed = window.getComputedStyle(element);\n    wrapper.style.color = computed.color;\n\n    var clone = element.cloneNode(true);\n    removeUiNoise(clone);\n    copyBoxTextStyle(element, clone);\n\n    wrapper.appendChild(clone);\n    host.appendChild(wrapper);\n\n    return wrapper;\n  }\n\n  function shouldUseIntroCandidate(candidate, controls) {\n    if (!candidate) {\n      return false;\n    }\n\n    if (controls.contains(candidate)) {\n      return false;\n    }\n\n    if (findAncestorByClass(candidate, 'jb-quick-hide')) {\n      return false;\n    }\n\n    if (findAncestorByClass(candidate, 'author-post')) {\n      return false;\n    }\n\n    if (findAncestorByClass(candidate, 'content__row')) {\n      return false;\n    }\n\n    if (findAncestorByClass(candidate, 'content__form')) {\n      return false;\n    }\n\n    if (findAncestorByClass(candidate, 'form-subscribe')) {\n      return false;\n    }\n\n    var text = cleanText(candidate.textContent);\n    if (text.length < 8) {\n      return false;\n    }\n\n    return true;\n  }\n\n  function collectIntroCandidates(contentRoot, controls) {\n    var result = [];\n    var candidates = contentRoot.querySelectorAll('h1, p, ol, ul');\n    var started = false;\n    var i;\n\n    for (i = 0; i < candidates.length; i += 1) {\n      var candidate = candidates[i];\n\n      if (!shouldUseIntroCandidate(candidate, controls)) {\n        continue;\n      }\n\n      var candidateText = cleanText(candidate.textContent);\n      var tagName = candidate.tagName ? candidate.tagName.toUpperCase() : '';\n\n      if (!started) {\n        if (tagName === 'H1') {\n          started = true;\n        } else {\n          if (candidateText.indexOf('Two valid ways of writing code') !== -1) {\n            started = true;\n          } else {\n            if (candidateText.indexOf('There are two ways developers create code now') !== -1) {\n              started = true;\n            }\n          }\n        }\n      }\n\n      if (!started) {\n        continue;\n      }\n\n      result.push(candidate);\n\n      if (candidateText.indexOf('Either way, one thing') !== -1) {\n        break;\n      }\n    }\n\n    return result;\n  }\n\n  function buildFallbackIntroClones(introCandidates, host, controls) {\n    var wrappers = [];\n    var controlRect = controls.getBoundingClientRect();\n    var top = controlRect.bottom + 18;\n    var i;\n\n    if (top < 24) {\n      top = 24;\n    }\n\n    if (top > window.innerHeight - 160) {\n      top = Math.max(24, window.innerHeight - 260);\n    }\n\n    for (i = 0; i < introCandidates.length; i += 1) {\n      var candidate = introCandidates[i];\n      var candidateText = cleanText(candidate.textContent);\n      var tagName = candidate.tagName ? candidate.tagName.toUpperCase() : '';\n\n      if (tagName === 'H1') {\n        continue;\n      }\n\n      if (controls.contains(candidate)) {\n        continue;\n      }\n\n      var rect = candidate.getBoundingClientRect();\n      if (rect.width < 12) {\n        continue;\n      }\n      if (rect.height < 8) {\n        continue;\n      }\n\n      var wrapper = document.createElement('div');\n      wrapper.className = 'jb-matrix-wrap';\n      wrapper._jbSourceElement = null;\n      wrapper.setAttribute('aria-hidden', 'true');\n      wrapper.style.left = rect.left + 'px';\n      wrapper.style.top = top + 'px';\n      wrapper.style.width = rect.width + 'px';\n      wrapper.style.minHeight = rect.height + 'px';\n\n      var computed = window.getComputedStyle(candidate);\n      wrapper.style.color = computed.color;\n\n      var clone = candidate.cloneNode(true);\n      removeUiNoise(clone);\n      copyBoxTextStyle(candidate, clone);\n\n      wrapper.appendChild(clone);\n      host.appendChild(wrapper);\n      wrappers.push(wrapper);\n\n      top += rect.height + 16;\n\n      if (candidateText.indexOf('Either way, one thing') !== -1) {\n        break;\n      }\n\n      if (wrappers.length >= 6) {\n        break;\n      }\n\n      if (top > window.innerHeight - 16) {\n        break;\n      }\n    }\n\n    return wrappers;\n  }\n\n  function buildIntroClones(contentRoot, controls, host) {\n    var wrappers = [];\n    var introCandidates = collectIntroCandidates(contentRoot, controls);\n    var i;\n\n    for (i = 0; i < introCandidates.length; i += 1) {\n      var candidate = introCandidates[i];\n      var rect = candidate.getBoundingClientRect();\n\n      if (!isRectOnScreen(rect)) {\n        continue;\n      }\n\n      var wrapper = buildFixedCloneFromElement(candidate, host);\n      if (wrapper) {\n        wrappers.push(wrapper);\n      }\n    }\n\n    if (!wrappers.length) {\n      wrappers = buildFallbackIntroClones(introCandidates, host, controls);\n    }\n\n    return wrappers;\n  }\n\n  function sourceIsHiddenSection(source) {\n    if (!source) {\n      return false;\n    }\n\n    if (source.classList) {\n      if (source.classList.contains('jb-quick-hide')) {\n        return true;\n      }\n    }\n\n    if (findAncestorByClass(source, 'jb-quick-hide')) {\n      return true;\n    }\n\n    return false;\n  }\n\n  function collectSourcesFromWrappers(wrappers) {\n    var sources = [];\n    var i;\n\n    for (i = 0; i < wrappers.length; i += 1) {\n      var wrapper = wrappers[i];\n      var source = wrapper ? wrapper._jbSourceElement : null;\n\n      if (!source) {\n        continue;\n      }\n\n      var alreadyAdded = false;\n      var j;\n      for (j = 0; j < sources.length; j += 1) {\n        if (sources[j] === source) {\n          alreadyAdded = true;\n          break;\n        }\n      }\n\n      if (!alreadyAdded) {\n        sources.push(source);\n      }\n    }\n\n    return sources;\n  }\n\n  function rememberSourceOpacity(source) {\n    if (!source) {\n      return;\n    }\n\n    if (source._jbQuickOpacityMemory) {\n      return;\n    }\n\n    source._jbQuickOpacityMemory = {\n      opacity: source.style.opacity,\n      transition: source.style.transition,\n      webkitTransition: source.style.webkitTransition\n    };\n  }\n\n  function fadeSourcesToZero(wrappers) {\n    var sources = collectSourcesFromWrappers(wrappers);\n    var i;\n\n    for (i = 0; i < sources.length; i += 1) {\n      rememberSourceOpacity(sources[i]);\n      sources[i].style.webkitTransition = 'opacity 460ms cubic-bezier(.22, 1, .36, 1)';\n      sources[i].style.transition = 'opacity 460ms cubic-bezier(.22, 1, .36, 1)';\n    }\n\n    requestAnimationFrame(function () {\n      var j;\n      for (j = 0; j < sources.length; j += 1) {\n        sources[j].style.opacity = '0';\n      }\n    });\n  }\n\n  function restoreSourcesFromZero(wrappers) {\n    var sources = collectSourcesFromWrappers(wrappers);\n    var i;\n\n    for (i = 0; i < sources.length; i += 1) {\n      var source = sources[i];\n      if (sourceIsHiddenSection(source)) {\n        continue;\n      }\n\n      rememberSourceOpacity(source);\n      source.style.webkitTransition = 'opacity 420ms cubic-bezier(.22, 1, .36, 1)';\n      source.style.transition = 'opacity 420ms cubic-bezier(.22, 1, .36, 1)';\n      source.style.opacity = '1';\n    }\n\n    window.setTimeout(function () {\n      var j;\n      for (j = 0; j < sources.length; j += 1) {\n        var current = sources[j];\n        var memory = current ? current._jbQuickOpacityMemory : null;\n\n        if (!memory) {\n          continue;\n        }\n\n        if (sourceIsHiddenSection(current)) {\n          continue;\n        }\n\n        current.style.opacity = memory.opacity;\n        current.style.transition = memory.transition;\n        current.style.webkitTransition = memory.webkitTransition;\n        current._jbQuickOpacityMemory = null;\n      }\n    }, 460);\n  }\n\n  function animateWrapper(wrapper) {\n    if (wrapper.classList) {\n      wrapper.classList.add('jb-matrix-active');\n    } else {\n      wrapper.className += ' jb-matrix-active';\n    }\n\n    runMatrixTextPass(wrapper);\n    return 1020;\n  }\n\n  function setTocVisibility(section, visible) {\n    var toc = document.querySelector('.js-toc');\n    if (!toc) {\n      return;\n    }\n\n    var headings = section.querySelectorAll('h1, h2, h3, h4, h5, h6');\n    var links = toc.querySelectorAll('a');\n    var i;\n\n    for (i = 0; i < headings.length; i += 1) {\n      var heading = headings[i];\n      if (!heading.id) {\n        continue;\n      }\n\n      var j;\n      for (j = 0; j < links.length; j += 1) {\n        var href = links[j].getAttribute('href') ? links[j].getAttribute('href') : '';\n        if (href.indexOf('#' + heading.id) !== -1) {\n          var item = findAncestorByClass(links[j], 'toc-list-item');\n          if (!item) {\n            item = links[j].parentNode;\n          }\n          if (item) {\n            item.style.display = visible ? '' : 'none';\n          }\n        }\n      }\n    }\n  }\n\n  function collapseSection(section, immediate) {\n    var computedStyle = window.getComputedStyle(section);\n\n    section.setAttribute('data-jb-height', section.offsetHeight);\n    section.setAttribute('data-jb-margin-top', computedStyle.marginTop);\n    section.setAttribute('data-jb-margin-bottom', computedStyle.marginBottom);\n\n    section.style.height = section.offsetHeight + 'px';\n    section.style.marginTop = computedStyle.marginTop;\n    section.style.marginBottom = computedStyle.marginBottom;\n    if (section.style.opacity === '0') {\n      section.style.opacity = '0';\n    } else {\n      section.style.opacity = '1';\n    }\n    section.style.visibility = 'hidden';\n    section.style.pointerEvents = 'none';\n    section.style.overflow = 'hidden';\n\n    if (immediate) {\n      section.style.height = '0px';\n      section.style.marginTop = '0px';\n      section.style.marginBottom = '0px';\n      section.style.opacity = '0';\n      return;\n    }\n\n    section.style.webkitTransition = 'height 460ms ease, margin 460ms ease, opacity 220ms ease';\n    section.style.transition = 'height 460ms ease, margin 460ms ease, opacity 220ms ease';\n\n    requestAnimationFrame(function () {\n      section.style.height = '0px';\n      section.style.marginTop = '0px';\n      section.style.marginBottom = '0px';\n      section.style.opacity = '0';\n    });\n  }\n\n  function expandSection(section, immediate) {\n    var targetHeight = section.getAttribute('data-jb-height') ? section.getAttribute('data-jb-height') : section.scrollHeight;\n    var targetMarginTop = section.getAttribute('data-jb-margin-top') ? section.getAttribute('data-jb-margin-top') : '';\n    var targetMarginBottom = section.getAttribute('data-jb-margin-bottom') ? section.getAttribute('data-jb-margin-bottom') : '';\n\n    section.style.display = '';\n    section.style.overflow = 'hidden';\n    section.style.pointerEvents = 'none';\n    section.style.visibility = '';\n\n    if (immediate) {\n      section.style.height = '';\n      section.style.marginTop = '';\n      section.style.marginBottom = '';\n      section.style.opacity = '';\n      section.style.visibility = '';\n      section.style.pointerEvents = '';\n      section.style.overflow = '';\n      section.style.webkitTransition = '';\n      section.style.transition = '';\n      section._jbQuickOpacityMemory = null;\n      return;\n    }\n\n    section.style.height = '0px';\n    section.style.marginTop = '0px';\n    section.style.marginBottom = '0px';\n    section.style.opacity = '0';\n    section.style.webkitTransition = 'height 460ms ease, margin 460ms ease, opacity 260ms ease';\n    section.style.transition = 'height 460ms ease, margin 460ms ease, opacity 260ms ease';\n\n    requestAnimationFrame(function () {\n      section.style.height = targetHeight + 'px';\n      section.style.marginTop = targetMarginTop;\n      section.style.marginBottom = targetMarginBottom;\n      section.style.opacity = '1';\n    });\n\n    window.setTimeout(function () {\n      section.style.height = '';\n      section.style.marginTop = '';\n      section.style.marginBottom = '';\n      section.style.opacity = '';\n      section.style.visibility = '';\n      section.style.pointerEvents = '';\n      section.style.overflow = '';\n      section.style.webkitTransition = '';\n      section.style.transition = '';\n      section._jbQuickOpacityMemory = null;\n    }, 520);\n  }\n\n  ready(function () {\n    var controls = document.querySelector('[data-jb-quick-controls]');\n    if (!controls) {\n      return;\n    }\n\n    if (!isSupported()) {\n      controls.style.display = 'none';\n      return;\n    }\n\n    var toggleButton = controls.querySelector('.jb-quick-toggle');\n    var status = controls.querySelector('.jb-quick-status');\n    var sections = toArray(document.querySelectorAll('.jb-quick-hide'));\n\n    if (!toggleButton) {\n      controls.style.display = 'none';\n      return;\n    }\n\n    if (!status) {\n      controls.style.display = 'none';\n      return;\n    }\n\n    if (!sections.length) {\n      controls.style.display = 'none';\n      return;\n    }\n\n    var contentRoot = findAncestorByClass(controls, 'js-toc-content');\n    if (!contentRoot) {\n      contentRoot = findAncestorByClass(controls, 'content');\n    }\n    if (!contentRoot) {\n      contentRoot = document.body;\n    }\n\n    var overlayHost = contentRoot.querySelector('.jb-matrix-host');\n    if (!overlayHost) {\n      overlayHost = document.createElement('div');\n      overlayHost.className = 'jb-matrix-host';\n      overlayHost.setAttribute('aria-hidden', 'true');\n      contentRoot.appendChild(overlayHost);\n    }\n\n    if (controls.classList) {\n      controls.classList.add('jb-quick-ready');\n    } else {\n      controls.className += ' jb-quick-ready';\n    }\n\n    controls.setAttribute('data-jb-mode', 'full');\n\n    var shortModeOn = false;\n    var busy = false;\n    var reduceMotion = prefersReducedMotion();\n\n    function runVisibleMatrixPass() {\n      var pass = { wrappers: [], longestAnimation: 0 };\n      var i;\n\n      if (reduceMotion) {\n        return pass;\n      }\n\n      pass.wrappers = buildIntroClones(contentRoot, controls, overlayHost);\n\n      if (pass.wrappers.length) {\n        fadeSourcesToZero(pass.wrappers);\n      }\n\n      for (i = 0; i < pass.wrappers.length; i += 1) {\n        var animationTime = animateWrapper(pass.wrappers[i]);\n        if (animationTime > pass.longestAnimation) {\n          pass.longestAnimation = animationTime;\n        }\n      }\n\n      return pass;\n    }\n\n    function cleanupMatrixPass(wrappers) {\n      var i;\n\n      restoreSourcesFromZero(wrappers);\n\n      for (i = 0; i < wrappers.length; i += 1) {\n        var currentWrapper = wrappers[i];\n        if (currentWrapper) {\n          if (currentWrapper.parentNode) {\n            currentWrapper.parentNode.removeChild(currentWrapper);\n          }\n        }\n      }\n    }\n\n    function hideMode() {\n      if (busy) {\n        return;\n      }\n\n      if (shortModeOn) {\n        return;\n      }\n\n      busy = true;\n      status.textContent = '';\n\n      var wrappers = [];\n      var i;\n      var longestAnimation = 0;\n\n      if (!reduceMotion) {\n        for (i = 0; i < sections.length; i += 1) {\n          setTocVisibility(sections[i], false);\n\n          var sectionWrapper = buildFixedCloneFromElement(sections[i], overlayHost);\n          if (sectionWrapper) {\n            wrappers.push(sectionWrapper);\n          }\n        }\n\n        if (!wrappers.length) {\n          wrappers = buildIntroClones(contentRoot, controls, overlayHost);\n        }\n\n        if (wrappers.length) {\n          fadeSourcesToZero(wrappers);\n        }\n\n        for (i = 0; i < wrappers.length; i += 1) {\n          var animationTime = animateWrapper(wrappers[i]);\n          if (animationTime > longestAnimation) {\n            longestAnimation = animationTime;\n          }\n        }\n      } else {\n        for (i = 0; i < sections.length; i += 1) {\n          setTocVisibility(sections[i], false);\n        }\n      }\n\n      var collapseDelay = longestAnimation + 40;\n      if (collapseDelay < 180) {\n        collapseDelay = 180;\n      }\n\n      window.setTimeout(function () {\n        var j;\n        for (j = 0; j < sections.length; j += 1) {\n          collapseSection(sections[j], reduceMotion);\n        }\n      }, reduceMotion ? 0 : collapseDelay);\n\n      var cleanupDelay = longestAnimation + 90;\n      if (cleanupDelay < 900) {\n        cleanupDelay = 900;\n      }\n\n      window.setTimeout(function () {\n        cleanupMatrixPass(wrappers);\n\n        shortModeOn = true;\n        busy = false;\n        controls.setAttribute('data-jb-mode', 'short');\n        toggleButton.textContent = 'annuler';\n        toggleButton.setAttribute('aria-pressed', 'true');\n        status.textContent = 'Version rapide activ\u00e9e.';\n      }, reduceMotion ? 40 : cleanupDelay);\n    }\n\n    function showMode() {\n      if (busy) {\n        return;\n      }\n\n      if (!shortModeOn) {\n        return;\n      }\n\n      busy = true;\n      status.textContent = '';\n\n      var matrixPass = runVisibleMatrixPass();\n      var expandDelay = matrixPass.longestAnimation ? 160 : 0;\n\n      window.setTimeout(function () {\n        var i;\n        for (i = 0; i < sections.length; i += 1) {\n          setTocVisibility(sections[i], true);\n          expandSection(sections[i], reduceMotion);\n        }\n      }, reduceMotion ? 0 : expandDelay);\n\n      var cleanupDelay = matrixPass.longestAnimation + 90;\n      if (cleanupDelay < 900) {\n        cleanupDelay = 900;\n      }\n\n      window.setTimeout(function () {\n        cleanupMatrixPass(matrixPass.wrappers);\n\n        shortModeOn = false;\n        busy = false;\n        controls.setAttribute('data-jb-mode', 'full');\n        toggleButton.textContent = 'press here';\n        toggleButton.setAttribute('aria-pressed', 'false');\n        status.textContent = 'Version compl\u00e8te restaur\u00e9e.';\n      }, reduceMotion ? 40 : cleanupDelay);\n    }\n\n    toggleButton.addEventListener('click', function () {\n      if (shortModeOn) {\n        showMode();\n      } else {\n        hideMode();\n      }\n    });\n  });\n}());\n<\/script>\n\n\n\n<p>Les d\u00e9veloppeurs peuvent maintenant cr\u00e9er du code de deux fa\u00e7ons :<\/p>\n\n\n\n<ol>\n<li>La m\u00e9thode classique : en saisissant du code, en le refactorisant, en le d\u00e9boguant et en obtenant le r\u00e9sultat souhait\u00e9 ligne par ligne.<\/li>\n\n\n\n<li>La nouvelle m\u00e9thode : en collaborant avec l'IA, parfois avec la saisie semi-automatique, et d'autres fois en utilisant un agent capable d'\u00e9laborer des pans entiers du travail.<\/li>\n<\/ol>\n\n\n\n<p><strong>Nous ne consid\u00e9rons pas que l'une est meilleure que l'autre.<\/strong><\/p>\n\n\n\n<p>Notre objectif est de garantir que les deux workflows puissent <strong>coexister dans les JetBrains IDEs<\/strong> sans interf\u00e9rer l'un avec l'autre. En pratique, cela signifie que&nbsp;:<\/p>\n\n\n\n<ul>\n<li>Si vous voulez \u00e9crire du code vous-m\u00eame, l'IDE doit se concentrer sur cela, et l'IA ne doit pas nuire \u00e0 l'exp\u00e9rience de programmation de base.<\/li>\n\n\n\n<li>Si vous souhaitez g\u00e9n\u00e9rer du code avec l'IA (ou d\u00e9l\u00e9guer des t\u00e2ches \u00e0 des agents), l'IDE doit rentre cette exp\u00e9rience naturelle et puissante, \u00e0 la fois en termes d'exp\u00e9rience utilisateur et de fonctionnalit\u00e9s.<\/li>\n<\/ul>\n\n\n\n<p>Dans tous les cas, une chose demeure inchang\u00e9e : <strong>un humain est responsable du code qu'il livre. <\/strong>Et le meilleur endroit pour lire, comprendre et ma\u00eetriser ce code reste l'IDE.<\/p>\n\n\n\n<div class=\"wp-block-group jb-quick-hide is-layout-flow wp-block-group-is-layout-flow\">\n<div class=\"wp-block-group__inner-container\"><hr class=\"wp-block-separator has-alpha-channel-opacity\">\n<h2 class=\"wp-block-heading\"><strong>Ce que signifie \u00ab l'IA dans l'IDE \u00bb, sans poudre aux yeux ni effet de mode<\/strong><\/h2>\n<p>Nous ne nous limitons pas \u00e0 un seul workflow \u00ab officiel \u00bb. Le march\u00e9 \u00e9volue trop vite pour cela, et les d\u00e9veloppeurs sont trop diff\u00e9rents pour une approche unique.<\/p>\n<p>Ainsi, lorsque nous parlons de \u00ab l'IA dans les JetBrains IDEs \u00bb, nous faisons r\u00e9f\u00e9rence \u00e0 la valeur ajout\u00e9e apport\u00e9e par les agents, c'est-\u00e0-dire \u00e0 l'exp\u00e9rience utilisateur et aux fonctionnalit\u00e9s qui deviennent disponibles si et quand elles sont utiles :<\/p>\n<ul>\n<li>Dans la fen\u00eatre d'outils <em>AI Chat<\/em>, pour un workflow <strong>ax\u00e9 en priorit\u00e9 sur le chat<\/strong>.<\/li>\n<li>Dans le <strong>terminal de l'IDE<\/strong>, o\u00f9 beaucoup de d\u00e9veloppeurs travaillent d\u00e9j\u00e0 avec des outils en ligne de commande.<\/li>\n<li>Dans les nouveaux <strong>modes optionnels<\/strong> cr\u00e9\u00e9s pour les syst\u00e8mes agentiques qui vous permettent d'ex\u00e9cuter un agent et de le laisser fonctionner pendant des heures.<\/li>\n<\/ul>\n<p>On peut voir cela comme suit : un m\u00eame IDE disposant de plusieurs moyens d'effectuer votre travail \u00e0 l'aide de l'IA \u2013 des moyens s\u00e9lectionn\u00e9s par l'utilisateur, d\u00e9finis par l'\u00e9quipe et limit\u00e9s par les attentes r\u00e9elles du d\u00e9veloppement.<\/p>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-group jb-quick-hide is-layout-flow wp-block-group-is-layout-flow\">\n<div class=\"wp-block-group__inner-container\"><hr class=\"wp-block-separator has-alpha-channel-opacity\">\n<h2 class=\"wp-block-heading\"><strong>La strat\u00e9gie en mati\u00e8re d'IA : \u00e9viter de d\u00e9pendre d'un fournisseur et maintenir des workflows compatibles<\/strong><\/h2>\n<p>S'il y a une chose dont nous sommes s\u00fbrs, c'est que le \u00ab meilleur \u00bb mod\u00e8le, fournisseur ou agent aujourd'hui ne restera pas le meilleur pour toujours, et ne le sera peut-\u00eatre d\u00e9j\u00e0 plus le mois prochain.<\/p>\n<p>C'est pourquoi nous optons d\u00e9lib\u00e9r\u00e9ment pour une exp\u00e9rience d'IDE qui ne d\u00e9pende <strong>pas<\/strong> de la feuille de route d'un seul fournisseur.<\/p>\n<p>Concr\u00e8tement, cela signifie que notre exp\u00e9rience de chat avec l'IA prend en charge plusieurs modes de connexion, dans le respect des conditions g\u00e9n\u00e9rales des fournisseurs et en fonction de ce que les utilisateurs veulent r\u00e9ellement :<\/p>\n<ul>\n<li><strong>La configuration g\u00e9r\u00e9e par JetBrains AI<\/strong> (avec un abonnement \u00e0 JetBrains AI).<\/li>\n<li><strong>Le BYOK<\/strong> : vous apportez votre propre cl\u00e9 API.<\/li>\n<li><strong>L'authentification OAuth<\/strong> pour les comptes fournisseurs compatibles (quand le fournisseur la prend en charge).<\/li>\n<li><strong>Les agents ACP<\/strong> : vous connectez des agents de programmation externes \u00e0 l'aide d'un protocole standard.<\/li>\n<\/ul>\n<p>Notez bien : <strong>OAuth n'est pas toujours disponible<\/strong>. Si un fournisseur d'agents ne propose pas l'authentification OAuth (ou pas de mani\u00e8re exploitable par un IDE), nous ne pouvons pas l'inventer.<\/p>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-group jb-quick-hide is-layout-flow wp-block-group-is-layout-flow\">\n<div class=\"wp-block-group__inner-container\"><hr class=\"wp-block-separator has-alpha-channel-opacity\">\n<h2 class=\"wp-block-heading\">L'Agent Client Protocol (ACP) : \u00ab Apportez votre propre agent \u00bb<\/h2>\n<p>L'ACP vous permet de connecter des agents de programmation externes aux JetBrains IDEs via une interface standard, de sorte que l'IDE n'a pas besoin d'une int\u00e9gration sp\u00e9cifique pour chaque agent. Les agents peuvent \u00eatre install\u00e9s \u00e0 partir d'un <a href=\"https:\/\/github.com\/agentclientprotocol\/registry\" target=\"_blank\" rel=\"noopener\">registre<\/a> organis\u00e9 (ou configur\u00e9s manuellement) et appara\u00eetront ensuite dans le chat IA.&nbsp;<\/p>\n<p>En pratique, les utilisateurs ont par exemple demand\u00e9 l'<strong>agent Cursor<\/strong>. Cursor est d\u00e9j\u00e0 disponible en tant qu'agent d'IA dans les JetBrains IDEs via l'ACP. Vous pouvez le s\u00e9lectionner dans le s\u00e9lecteur d'agent et utiliser son workflow agentique dans votre JetBrains IDE.&nbsp;<\/p>\n<p>Voici le mod\u00e8le que nous voulons suivre :<\/p>\n<ul>\n<li>Vous choisissez l'agent qui correspond \u00e0 votre workflow ou \u00e0 votre \u00e9quipe.<\/li>\n<li>Vous continuez \u00e0 travailler dans l'IDE que vous ma\u00eetrisez d\u00e9j\u00e0.<\/li>\n<li>Les workflows d'IDE classiques ne sont pas mis de c\u00f4t\u00e9 par le \u00ab mode agent \u00bb.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-group jb-quick-hide is-layout-flow wp-block-group-is-layout-flow\">\n<div class=\"wp-block-group__inner-container\"><hr class=\"wp-block-separator has-alpha-channel-opacity\">\n<h2 class=\"wp-block-heading\"><strong>Une \u00ab programmation professionnelle avec l'IA \u00bb implique plus de responsabilit\u00e9s<\/strong><\/h2>\n<p>Nous ne sommes pas contre l'IA. Nous sommes contre la confusion.<\/p>\n<p>ll existe un type de programmation optimis\u00e9 pour des r\u00e9sultats jetables \u2013 et il est parfaitement valable dans les bons contextes. Mais les JetBrains IDEs sont con\u00e7us non pas pour du code jetable, mais plut\u00f4t pour du code destin\u00e9 \u00e0 une utilisation \u00e0 long terme.<\/p>\n<p>Ainsi, lors du d\u00e9veloppement de nos IDE, nous appliquons le principe selon lequel <strong>tout code g\u00e9n\u00e9r\u00e9 doit \u00eatre trait\u00e9 comme du code r\u00e9el. <\/strong>Il doit donc \u00eatre possible de :<\/p>\n<ul>\n<li>Le lire<\/li>\n<li>Le r\u00e9viser<\/li>\n<li>Le modifier<\/li>\n<li>Revenir en arri\u00e8re en cas d'erreur<\/li>\n<li>Comprendre son impact sur la base de code<\/li>\n<\/ul>\n<p>Concr\u00e8tement, nos attentes de base sont plut\u00f4t banales (dans le meilleur sens du terme) :<\/p>\n<ul>\n<li>Les modifications doivent \u00eatre <strong>visibles<\/strong><\/li>\n<li>Les modifications doivent \u00eatre <strong>r\u00e9versibles<\/strong><\/li>\n<li>Votre projet ne se retrouve pas dans un \u00e9tat dysfonctionnel (l'absence de code rouge est un assez bon point de d\u00e9part)<\/li>\n<\/ul>\n<p>Et oui, les agents peuvent modifier un grand nombre de fichiers. Cela peut \u00eatre un super-pouvoir, mais uniquement si vous pouvez enti\u00e8rement inspecter, comprendre et corriger le r\u00e9sultat. C'est l\u00e0 que l'IDE fait la diff\u00e9rence : il vous offre visibilit\u00e9 et contr\u00f4le sur le code, qu'il soit produit par des humains ou une IA.<\/p>\n<\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">L'IA selon vos conditions : nos engagements dans nos produits<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Les modes IA et classique se c\u00f4toient&nbsp;<\/h3>\n\n\n\n<p>Les workflows ax\u00e9s sur la saisie et ceux ax\u00e9s sur l'IA sont tous deux valides. Nous ne travaillons pas \u00e0 alimenter les discours sur le remplacement des d\u00e9veloppeurs, et nous ne cr\u00e9ons pas non plus d'IDE qui vous incitent \u00e0 adopter une seule m\u00e9thode de travail \u00ab approuv\u00e9e \u00bb. Nous respectons les deux approches.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Les agents d'IA doivent respecter la promesse fondamentale de l'IDE<\/h3>\n\n\n\n<p>Chaque \u00e9tape d'adoption des agents doit pr\u00e9server la promesse fondamentale de l'IDE : intelligence du code approfondie, et des op\u00e9rations de refactorisation, de d\u00e9bogage, de navigation, d'inspection et de r\u00e9vision s\u00e9curis\u00e9es \u2013 tout ce qui fait l'essence m\u00eame du d\u00e9veloppement professionnel.<\/p>\n\n\n\n<div class=\"wp-block-group jb-quick-hide is-layout-flow wp-block-group-is-layout-flow\">\n<div class=\"wp-block-group__inner-container\">\n<h3 class=\"wp-block-heading\">3. Aucune d\u00e9pendance vis-\u00e0-vis d'un fournisseur<\/h3>\n<p>Les multiples voies d'activation (abonnement, BYOK, OAuth si possible, et agents ACP) ne sont pas un \u00ab bonus \u00bb. Nous nous engageons \u00e0 ce que votre workflow ne soit jamais li\u00e9 \u00e0 un seul fournisseur.<\/p>\n<h3 class=\"wp-block-heading\">4. L'utilit\u00e9 \u00e0 long terme pr\u00e9vaut sur les tendances<\/h3>\n<p>Si les gens continuent \u00e0 utiliser ces workflows des semaines plus tard (fid\u00e9lisation et projets concrets), c'est bon signe. De nombreux workflows pilot\u00e9s par l'IA ne sont aujourd'hui qu'une mode passag\u00e8re (comme Ralph-loop).&nbsp;<\/p>\n<h3 class=\"wp-block-heading\">5. Priorit\u00e9 aux retours d'exp\u00e9rience sinc\u00e8res de la communaut\u00e9<\/h3>\n<p>Nous appr\u00e9cions l'honn\u00eatet\u00e9 des utilisateurs de Reddit, des \u00e9valuateurs de la Marketplace et des membres de la communaut\u00e9, qui ne sont pas tenus d'\u00eatre polis envers nous. Ce sont exactement ces personnes-l\u00e0 que nous voulons pour juger de nos progr\u00e8s.<\/p>\n<\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>L'IA va cr\u00e9er beaucoup de code. Ce n'est plus une pr\u00e9diction, c'est la r\u00e9alit\u00e9 en avril 2026.<\/p>\n\n\n\n<p>Mais il faut bien que quelqu'un soit responsable de ce code. Il faut encore que quelqu'un le lise avant la fusion. Et \u00e0 l'heure actuelle, les agents peuvent vous aider \u00e0 aller plus vite, mais ils ne peuvent pas assumer ce risque pour vous.<\/p>\n\n\n\n<p>Notre engagement est donc simple :<\/p>\n\n\n\n<p><strong>Nous allons continuer \u00e0 mettre au point des workflows d'IA qui acc\u00e9l\u00e8rent la cr\u00e9ation, et \u00e0 renforcer l'IDE en tant que lieu id\u00e9al pour examiner, comprendre et assumer la responsabilit\u00e9 de ce qui est livr\u00e9.<\/strong><\/p>\n\n\n\n<p>Vous d\u00e9cidez de la dose d'IA qui vous convient. Nous veillerons \u00e0 ce que les deux parcours \u2013 classique et assist\u00e9 par l'IA \u2013 fonctionnent parfaitement ensemble, mais vous pouvez choisir celle que vous pr\u00e9f\u00e9rez.<\/p>\n\n\n\n<p><em>Auteur de l'article original en anglais<\/em> :<\/p>\n\n\n    <div class=\"about-author \">\n        <div class=\"about-author__box\">\n            <div class=\"row\">\n                <div class=\"about-author__box-img\">\n                    <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/10\/IMG_6963-e1759851102680-200x200.jpg\" width=\"200\" height=\"200\" alt=\"Denis Shiryaev\" loading=\"lazy\"  class=\"avatar avatar-200 wp-user-avatar wp-user-avatar-200 photo avatar-default\">\n                <\/div>\n                <div class=\"about-author__box-text\">\n                                            <h4>Denis Shiryaev<\/h4>\n                                                        <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n","protected":false},"author":813,"featured_media":702513,"comment_status":"closed","ping_status":"closed","template":"","categories":[],"tags":[8168],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ai\/706354"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ai"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/ai"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/813"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=706354"}],"version-history":[{"count":5,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ai\/706354\/revisions"}],"predecessor-version":[{"id":706528,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ai\/706354\/revisions\/706528"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/702513"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=706354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=706354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=706354"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=706354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}